diff options
Diffstat (limited to 'drivers/net')
225 files changed, 12053 insertions, 5103 deletions
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 62ceb2b4820..4d4cad393dc 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -249,11 +249,11 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) * for the Sager NP943 prefix. */ - if (station_addr[0] == 0x02 && station_addr[1] == 0x60 - && station_addr[2] == 0x8c) + if (station_addr[0] == 0x02 && station_addr[1] == 0x60 && + station_addr[2] == 0x8c) mname = "3c501"; - else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 - && station_addr[2] == 0xC8) + else if (station_addr[0] == 0x00 && station_addr[1] == 0x80 && + station_addr[2] == 0xC8) mname = "NP943"; else { release_region(ioaddr, EL1_IO_EXTENT); diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index c71e12d05f6..66e0323c183 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -214,8 +214,8 @@ el2_probe1(struct net_device *dev, int ioaddr) iobase_reg = inb(ioaddr+0x403); membase_reg = inb(ioaddr+0x404); /* ASIC location registers should be 0 or have only a single bit set. */ - if ( (iobase_reg & (iobase_reg - 1)) - || (membase_reg & (membase_reg - 1))) { + if ((iobase_reg & (iobase_reg - 1)) || + (membase_reg & (membase_reg - 1))) { retval = -ENODEV; goto out1; } @@ -291,8 +291,8 @@ el2_probe1(struct net_device *dev, int ioaddr) writel(0xba5eba5e, mem_base); for (i = sizeof(test_val); i < EL2_MEMSIZE; i+=sizeof(test_val)) { writel(test_val, mem_base + i); - if (readl(mem_base) != 0xba5eba5e - || readl(mem_base + i) != test_val) { + if (readl(mem_base) != 0xba5eba5e || + readl(mem_base + i) != test_val) { pr_warning("3c503: memory failure or memory address conflict.\n"); dev->mem_start = 0; ei_status.name = "3c503-PIO"; @@ -397,9 +397,10 @@ el2_open(struct net_device *dev) unsigned long cookie = probe_irq_on(); outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR); outb_p(0x00, E33G_IDCFR); - if (*irqp == probe_irq_off(cookie) /* It's a good IRQ line! */ - && ((retval = request_irq(dev->irq = *irqp, - eip_interrupt, 0, dev->name, dev)) == 0)) + if (*irqp == probe_irq_off(cookie) && /* It's a good IRQ line! */ + ((retval = request_irq(dev->irq = *irqp, + eip_interrupt, 0, + dev->name, dev)) == 0)) break; } else { if (retval != -EBUSY) diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 605f1d17a8f..fbc231153e5 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -836,8 +836,8 @@ static void el16_rx(struct net_device *dev) void __iomem *data_frame = lp->base + data_buffer_addr; ushort pkt_len = readw(data_frame); - if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 - || (pkt_len & 0xC000) != 0xC000) { + if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22 || + (pkt_len & 0xC000) != 0xC000) { pr_err("%s: Rx frame at %#x corrupted, " "status %04x cmd %04x next %04x " "data-buf @%04x %04x.\n", diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 8d4ce096407..9d85efce591 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -253,9 +253,9 @@ static int el3_isa_id_sequence(__be16 *phys_addr) This check is needed in order not to register them twice. */ for (i = 0; i < el3_cards; i++) { struct el3_private *lp = netdev_priv(el3_devs[i]); - if (lp->type == EL3_PNP - && !memcmp(phys_addr, el3_devs[i]->dev_addr, - ETH_ALEN)) { + if (lp->type == EL3_PNP && + !memcmp(phys_addr, el3_devs[i]->dev_addr, + ETH_ALEN)) { if (el3_debug > 3) pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", phys_addr[0] & 0xff, phys_addr[0] >> 8, @@ -835,8 +835,8 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev) #ifndef final_version { /* Error-checking code, delete someday. */ ushort status = inw(ioaddr + EL3_STATUS); - if (status & 0x0001 /* IRQ line active, missed one. */ - && inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */ + if (status & 0x0001 && /* IRQ line active, missed one. */ + inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */ pr_debug("%s: Missed interrupt, status then %04x now %04x" " Tx %2.2x Rx %4.4x.\n", dev->name, status, inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS), diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 37faf36e245..063b049ffe5 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -764,10 +764,11 @@ static int corkscrew_open(struct net_device *dev) /* Use the now-standard shared IRQ implementation. */ if (vp->capabilities == 0x11c7) { /* Corkscrew: Cannot share ISA resources. */ - if (dev->irq == 0 - || dev->dma == 0 - || request_irq(dev->irq, corkscrew_interrupt, 0, - vp->product_name, dev)) return -EAGAIN; + if (dev->irq == 0 || + dev->dma == 0 || + request_irq(dev->irq, corkscrew_interrupt, 0, + vp->product_name, dev)) + return -EAGAIN; enable_dma(dev->dma); set_dma_mode(dev->dma, DMA_MODE_CASCADE); } else if (request_irq(dev->irq, corkscrew_interrupt, IRQF_SHARED, @@ -1368,8 +1369,8 @@ static int boomerang_rx(struct net_device *dev) /* Check if the packet is long enough to just accept without copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 4)) != NULL) { + if (pkt_len < rx_copybreak && + (skb = dev_alloc_skb(pkt_len + 4)) != NULL) { skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index d91c3464fe7..36c4191e7bc 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -1168,8 +1168,8 @@ static void mc32_rx_ring(struct net_device *dev) /* Try to save time by avoiding a copy on big frames */ - if ((length > RX_COPYBREAK) - && ((newskb=dev_alloc_skb(1532)) != NULL)) + if ((length > RX_COPYBREAK) && + ((newskb=dev_alloc_skb(1532)) != NULL)) { skb=lp->rx_ring[rx_ring_tail].skb; skb_put(skb, length); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 32031eaf491..78b7167a8ce 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1942,8 +1942,8 @@ vortex_error(struct net_device *dev, int status) if (status & TxComplete) { /* Really "TxError" for us. */ tx_status = ioread8(ioaddr + TxStatus); /* Presumably a tx-timeout. We must merely re-enable. */ - if (vortex_debug > 2 - || (tx_status != 0x88 && vortex_debug > 0)) { + if (vortex_debug > 2 || + (tx_status != 0x88 && vortex_debug > 0)) { pr_err("%s: Transmit error, Tx status register %2.2x.\n", dev->name, tx_status); if (tx_status == 0x82) { diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index ab451bb8995..3f452bcbfb9 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -909,8 +909,8 @@ static void __cp_set_rx_mode (struct net_device *dev) AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 7e333f73b22..25f7339daab 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1549,8 +1549,8 @@ static inline void rtl8139_thread_iter (struct net_device *dev, mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA); if (!tp->mii.force_media && mii_lpa != 0xffff) { - int duplex = (mii_lpa & LPA_100FULL) - || (mii_lpa & 0x01C0) == 0x0040; + int duplex = ((mii_lpa & LPA_100FULL) || + (mii_lpa & 0x01C0) == 0x0040); if (tp->mii.full_duplex != duplex) { tp->mii.full_duplex = duplex; @@ -1936,8 +1936,8 @@ static int rtl8139_rx(struct net_device *dev, struct rtl8139_private *tp, RTL_R16 (RxBufAddr), RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); - while (netif_running(dev) && received < budget - && (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { + while (netif_running(dev) && received < budget && + (RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { u32 ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status; unsigned int pkt_size; @@ -2521,8 +2521,8 @@ static void __set_rx_mode (struct net_device *dev) AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 6399abbdad6..0bbd5ae4986 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -975,7 +975,7 @@ config ENC28J60_WRITEVERIFY config ETHOC tristate "OpenCores 10/100 Mbps Ethernet MAC support" - depends on NET_ETHERNET && HAS_IOMEM + depends on NET_ETHERNET && HAS_IOMEM && HAS_DMA select MII select PHYLIB select CRC32 diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index aaf14d306a4..eb0448b03f4 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -230,9 +230,9 @@ static int ipddp_delete(struct ipddp_route *rt) spin_lock_bh(&ipddp_route_lock); while((tmp = *r) != NULL) { - if(tmp->ip == rt->ip - && tmp->at.s_net == rt->at.s_net - && tmp->at.s_node == rt->at.s_node) + if(tmp->ip == rt->ip && + tmp->at.s_net == rt->at.s_net && + tmp->at.s_node == rt->at.s_node) { *r = tmp->next; spin_unlock_bh(&ipddp_route_lock); @@ -255,9 +255,9 @@ static struct ipddp_route* __ipddp_find_route(struct ipddp_route *rt) for(f = ipddp_route_list; f != NULL; f = f->next) { - if(f->ip == rt->ip - && f->at.s_net == rt->at.s_net - && f->at.s_node == rt->at.s_node) + if(f->ip == rt->ip && + f->at.s_net == rt->at.s_net && + f->at.s_node == rt->at.s_node) return (f); } diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index c5b988140a9..e6afab2455b 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -174,9 +174,9 @@ static int __init arcrimi_found(struct net_device *dev) * 2k (or there are no mirrors at all) but on some, it's 4k. */ mirror_size = MIRROR_SIZE; - if (readb(p) == TESTvalue - && check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 - && check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1) + if (readb(p) == TESTvalue && + check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 && + check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1) mirror_size = 2 * MIRROR_SIZE; first_mirror = shmem - mirror_size; diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 75a57256090..d8f02930375 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -301,8 +301,8 @@ static int choose_mtu(void) /* choose the smallest MTU of all available encaps */ for (count = 0; count < 256; count++) { - if (arc_proto_map[count] != &arc_proto_null - && arc_proto_map[count]->mtu < mtu) { + if (arc_proto_map[count] != &arc_proto_null && + arc_proto_map[count]->mtu < mtu) { mtu = arc_proto_map[count]->mtu; } } @@ -953,13 +953,13 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) * > RECON_THRESHOLD/min; * then print a warning message. */ - if (!lp->network_down - && (lp->last_recon - lp->first_recon) <= HZ * 60 - && lp->num_recons >= RECON_THRESHOLD) { + if (!lp->network_down && + (lp->last_recon - lp->first_recon) <= HZ * 60 && + lp->num_recons >= RECON_THRESHOLD) { lp->network_down = 1; BUGMSG(D_NORMAL, "many reconfigurations detected: cabling problem?\n"); - } else if (!lp->network_down - && lp->last_recon - lp->first_recon > HZ * 60) { + } else if (!lp->network_down && + lp->last_recon - lp->first_recon > HZ * 60) { /* reset counters if we've gone for over a minute. */ lp->first_recon = lp->last_recon; lp->num_recons = 1; diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 2be49c81799..b25467ac895 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -628,15 +628,6 @@ static int ep93xx_open(struct net_device *dev) if (ep93xx_alloc_buffers(ep)) return -ENOMEM; - if (is_zero_ether_addr(dev->dev_addr)) { - random_ether_addr(dev->dev_addr); - printk(KERN_INFO "%s: generated random MAC address " - "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); - } - napi_enable(&ep->napi); if (ep93xx_start_hw(dev)) { @@ -877,6 +868,9 @@ static int ep93xx_eth_probe(struct platform_device *pdev) ep->mii.mdio_write = ep93xx_mdio_write; ep->mdc_divisor = 40; /* Max HCLK 100 MHz, min MDIO clk 2.5 MHz. */ + if (is_zero_ether_addr(dev->dev_addr)) + random_ether_addr(dev->dev_addr); + err = register_netdev(dev); if (err) { dev_err(&pdev->dev, "Failed to register netdev\n"); diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index d4ab69f032b..b14f4799d5d 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -350,13 +350,13 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr) slot = -1; /* We must check for the EEPROM-config boards first, else accessing IOCONFIG0 will move the board! */ - if (at1700_probe_list[inb(ioaddr + IOCONFIG1) & 0x07] == ioaddr - && read_eeprom(ioaddr, 4) == 0x0000 - && (read_eeprom(ioaddr, 5) & 0xff00) == 0xF400) + if (at1700_probe_list[inb(ioaddr + IOCONFIG1) & 0x07] == ioaddr && + read_eeprom(ioaddr, 4) == 0x0000 && + (read_eeprom(ioaddr, 5) & 0xff00) == 0xF400) is_at1700 = 1; - else if (inb(ioaddr + SAPROM ) == 0x00 - && inb(ioaddr + SAPROM + 1) == 0x00 - && inb(ioaddr + SAPROM + 2) == 0x0e) + else if (inb(ioaddr + SAPROM ) == 0x00 && + inb(ioaddr + SAPROM + 1) == 0x00 && + inb(ioaddr + SAPROM + 2) == 0x0e) is_fmv18x = 1; else { goto err_out; @@ -839,8 +839,8 @@ set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { memset(mc_filter, 0xff, sizeof(mc_filter)); outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ - } else if (dev->mc_count > MC_FILTERBREAK - || (dev->flags & IFF_ALLMULTI)) { + } else if (dev->mc_count > MC_FILTERBREAK || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); outb(2, ioaddr + RX_MODE); /* Use normal mode. */ diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 0c0deceb693..c5721cb3826 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -930,8 +930,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) } #endif - if (lp->tx_full && (netif_queue_stopped(dev)) - && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + if (lp->tx_full && (netif_queue_stopped(dev)) && + dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; netif_wake_queue (dev); diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c index 60edb9f232b..a76006c1bc6 100644 --- a/drivers/net/atl1e/atl1e_ethtool.c +++ b/drivers/net/atl1e/atl1e_ethtool.c @@ -131,11 +131,6 @@ static int atl1e_set_settings(struct net_device *netdev, return 0; } -static u32 atl1e_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_HW_CSUM) != 0; -} - static u32 atl1e_get_msglevel(struct net_device *netdev) { #ifdef DBG @@ -145,10 +140,6 @@ static u32 atl1e_get_msglevel(struct net_device *netdev) #endif } -static void atl1e_set_msglevel(struct net_device *netdev, u32 data) -{ -} - static int atl1e_get_regs_len(struct net_device *netdev) { return AT_REGS_LEN * sizeof(u32); @@ -387,18 +378,14 @@ static const struct ethtool_ops atl1e_ethtool_ops = { .get_wol = atl1e_get_wol, .set_wol = atl1e_set_wol, .get_msglevel = atl1e_get_msglevel, - .set_msglevel = atl1e_set_msglevel, .nway_reset = atl1e_nway_reset, .get_link = ethtool_op_get_link, .get_eeprom_len = atl1e_get_eeprom_len, .get_eeprom = atl1e_get_eeprom, .set_eeprom = atl1e_set_eeprom, - .get_tx_csum = atl1e_get_tx_csum, - .get_sg = ethtool_op_get_sg, + .set_tx_csum = ethtool_op_set_tx_hw_csum, .set_sg = ethtool_op_set_sg, -#ifdef NETIF_F_TSO - .get_tso = ethtool_op_get_tso, -#endif + .set_tso = ethtool_op_set_tso, }; void atl1e_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index ad17e74e566..08f8c0969e9 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1664,41 +1664,6 @@ static int atl1e_tso_csum(struct atl1e_adapter *adapter, } return 0; } - - if (offload_type & SKB_GSO_TCPV6) { - real_len = (((unsigned char *)ipv6_hdr(skb) - skb->data) - + ntohs(ipv6_hdr(skb)->payload_len)); - if (real_len < skb->len) - pskb_trim(skb, real_len); - - /* check payload == 0 byte ? */ - hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb)); - if (unlikely(skb->len == hdr_len)) { - /* only xsum need */ - dev_warn(&pdev->dev, - "IPV6 tso with zero data??\n"); - goto check_sum; - } else { - tcp_hdr(skb)->check = ~csum_ipv6_magic( - &ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - 0, IPPROTO_TCP, 0); - tpd->word3 |= 1 << TPD_IP_VERSION_SHIFT; - hdr_len >>= 1; - tpd->word3 |= (hdr_len & TPD_V6_IPHLLO_MASK) << - TPD_V6_IPHLLO_SHIFT; - tpd->word3 |= ((hdr_len >> 3) & - TPD_V6_IPHLHI_MASK) << - TPD_V6_IPHLHI_SHIFT; - tpd->word3 |= (tcp_hdrlen(skb) >> 2 & - TPD_TCPHDRLEN_MASK) << - TPD_TCPHDRLEN_SHIFT; - tpd->word3 |= ((skb_shinfo(skb)->gso_size) & - TPD_MSS_MASK) << TPD_MSS_SHIFT; - tpd->word3 |= 1 << TPD_SEGMENT_EN_SHIFT; - } - } - return 0; } check_sum: @@ -2287,7 +2252,6 @@ static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev) NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; netdev->features |= NETIF_F_LLTX; netdev->features |= NETIF_F_TSO; - netdev->features |= NETIF_F_TSO6; return 0; } diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index e547f788a26..b6cf3263127 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -1344,8 +1344,8 @@ static u32 atl1_check_link(struct atl1_adapter *adapter) /* link result is our setting */ if (!reconfig) { - if (adapter->link_speed != speed - || adapter->link_duplex != duplex) { + if (adapter->link_speed != speed || + adapter->link_duplex != duplex) { adapter->link_speed = speed; adapter->link_duplex = duplex; atl1_setup_mac_ctrl(adapter); @@ -2087,8 +2087,8 @@ static void atl1_intr_tx(struct atl1_adapter *adapter) } atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean); - if (netif_queue_stopped(adapter->netdev) - && netif_carrier_ok(adapter->netdev)) + if (netif_queue_stopped(adapter->netdev) && + netif_carrier_ok(adapter->netdev)) netif_wake_queue(adapter->netdev); } diff --git a/drivers/net/atp.c b/drivers/net/atp.c index 001791775be..2f8261c9614 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -673,8 +673,8 @@ static irqreturn_t atp_interrupt(int irq, void *dev_instance) netif_wake_queue(dev); /* Inform upper layers. */ } num_tx_since_rx++; - } else if (num_tx_since_rx > 8 - && time_after(jiffies, dev->last_rx + HZ)) { + } else if (num_tx_since_rx > 8 && + time_after(jiffies, dev->last_rx + HZ)) { if (net_debug > 2) printk(KERN_DEBUG "%s: Missed packet? No Rx after %d Tx and " "%ld jiffies status %02x CMR1 %02x.\n", dev->name, diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index e67533cf78d..6bac04603a8 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -1088,7 +1088,14 @@ static struct net_device * au1000_probe(int port_num) return NULL; } - if ((err = register_netdev(dev)) != 0) { + dev->base_addr = base; + dev->irq = irq; + dev->netdev_ops = &au1000_netdev_ops; + SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops); + dev->watchdog_timeo = ETH_TX_TIMEOUT; + + err = register_netdev(dev); + if (err != 0) { printk(KERN_ERR "%s: Cannot register net device, error %d\n", DRV_NAME, err); free_netdev(dev); @@ -1209,12 +1216,6 @@ static struct net_device * au1000_probe(int port_num) aup->tx_db_inuse[i] = pDB; } - dev->base_addr = base; - dev->irq = irq; - dev->netdev_ops = &au1000_netdev_ops; - SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops); - dev->watchdog_timeo = ETH_TX_TIMEOUT; - /* * The boot code uses the ethernet controller, so reset it to start * fresh. au1000_init() expects that the device is in reset state. diff --git a/drivers/net/b44.c b/drivers/net/b44.c index e046943ef29..2a9132343b6 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -912,9 +912,6 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id) bp->istat = istat; __b44_disable_ints(bp); __napi_schedule(&bp->napi); - } else { - printk(KERN_ERR PFX "%s: Error, poll already scheduled\n", - dev->name); } irq_ack: diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index dc7c19e4911..9e56014d27e 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h @@ -32,7 +32,7 @@ #include "be_hw.h" -#define DRV_VER "2.101.205" +#define DRV_VER "2.101.346u" #define DRV_NAME "be2net" #define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC" #define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC" @@ -170,7 +170,7 @@ struct be_drvr_stats { u32 cache_barrier[16]; u32 be_ethrx_post_fail;/* number of ethrx buffer alloc failures */ - u32 be_polls; /* number of times NAPI called poll function */ + u32 be_rx_polls; /* number of times NAPI called poll function */ u32 be_rx_events; /* number of ucast rx completion events */ u32 be_rx_compl; /* number of rx completion entries processed */ ulong be_rx_jiffies; @@ -269,9 +269,12 @@ struct be_adapter { bool link_up; u32 port_num; bool promiscuous; + bool wol; u32 cap; u32 rx_fc; /* Rx flow control */ u32 tx_fc; /* Tx flow control */ + int link_speed; + u8 port_type; }; extern const struct ethtool_ops be_ethtool_ops; diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 8bd53156004..1b68bd98dc0 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -71,8 +71,8 @@ static int be_mcc_compl_process(struct be_adapter *adapter, extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & CQE_STATUS_EXTD_MASK; dev_warn(&adapter->pdev->dev, - "Error in cmd completion: status(compl/extd)=%d/%d\n", - compl_status, extd_status); + "Error in cmd completion - opcode %d, compl %d, extd %d\n", + compl->tag0, compl_status, extd_status); } return compl_status; } @@ -277,7 +277,7 @@ static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb) /* Don't touch the hdr after it's prepared */ static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, - bool embedded, u8 sge_cnt) + bool embedded, u8 sge_cnt, u32 opcode) { if (embedded) wrb->embedded |= MCC_WRB_EMBEDDED_MASK; @@ -285,6 +285,7 @@ static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) << MCC_WRB_SGE_CNT_SHIFT; wrb->payload_length = payload_len; + wrb->tag0 = opcode; be_dws_cpu_to_le(wrb, 20); } @@ -425,7 +426,7 @@ int be_cmd_eq_create(struct be_adapter *adapter, wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_COMMON_EQ_CREATE); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_EQ_CREATE, sizeof(*req)); @@ -469,7 +470,8 @@ int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_MAC_QUERY); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req)); @@ -509,7 +511,8 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_PMAC_ADD); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req)); @@ -544,7 +547,8 @@ int be_cmd_pmac_del(struct be_adapter *adapter, u32 if_id, u32 pmac_id) } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_PMAC_DEL); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req)); @@ -576,7 +580,8 @@ int be_cmd_cq_create(struct be_adapter *adapter, req = embedded_payload(wrb); ctxt = &req->context; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_CQ_CREATE); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_CQ_CREATE, sizeof(*req)); @@ -633,7 +638,8 @@ int be_cmd_mccq_create(struct be_adapter *adapter, req = embedded_payload(wrb); ctxt = &req->context; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MCC_CREATE); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_MCC_CREATE, sizeof(*req)); @@ -677,7 +683,8 @@ int be_cmd_txq_create(struct be_adapter *adapter, req = embedded_payload(wrb); ctxt = &req->context; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_ETH_TX_CREATE); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_TX_CREATE, sizeof(*req)); @@ -724,7 +731,8 @@ int be_cmd_rxq_create(struct be_adapter *adapter, wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_ETH_RX_CREATE); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_CREATE, sizeof(*req)); @@ -765,8 +773,6 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - switch (queue_type) { case QTYPE_EQ: subsys = CMD_SUBSYSTEM_COMMON; @@ -791,6 +797,9 @@ int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q, default: BUG(); } + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, opcode); + be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); req->id = cpu_to_le16(q->id); @@ -816,7 +825,8 @@ int be_cmd_if_create(struct be_adapter *adapter, u32 cap_flags, u32 en_flags, wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_INTERFACE_CREATE); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req)); @@ -851,7 +861,8 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id) wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_INTERFACE_DESTROY); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req)); @@ -886,8 +897,8 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) req = nonemb_cmd->va; sge = nonembedded_sgl(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - wrb->tag0 = OPCODE_ETH_GET_STATISTICS; + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + OPCODE_ETH_GET_STATISTICS); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_GET_STATISTICS, sizeof(*req)); @@ -921,7 +932,8 @@ int be_cmd_link_status_query(struct be_adapter *adapter, *link_up = false; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_LINK_STATUS_QUERY); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req)); @@ -953,7 +965,8 @@ int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver) wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_GET_FW_VERSION); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_FW_VERSION, sizeof(*req)); @@ -986,7 +999,8 @@ int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd) } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MODIFY_EQ_DELAY); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req)); @@ -1020,7 +1034,8 @@ int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id, u16 *vtag_array, } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_NTWK_VLAN_CONFIG); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req)); @@ -1059,7 +1074,7 @@ int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en) } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_ETH_PROMISCUOUS); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_PROMISCUOUS, sizeof(*req)); @@ -1099,7 +1114,8 @@ int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id, sge = nonembedded_sgl(wrb); memset(req, 0, sizeof(*req)); - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + OPCODE_COMMON_NTWK_MULTICAST_SET); sge->pa_hi = cpu_to_le32(upper_32_bits(mem->dma)); sge->pa_lo = cpu_to_le32(mem->dma & 0xFFFFFFFF); sge->len = cpu_to_le32(mem->size); @@ -1143,7 +1159,8 @@ int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc) } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_SET_FLOW_CONTROL); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_SET_FLOW_CONTROL, sizeof(*req)); @@ -1174,7 +1191,8 @@ int be_cmd_get_flow_control(struct be_adapter *adapter, u32 *tx_fc, u32 *rx_fc) } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_GET_FLOW_CONTROL); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req)); @@ -1204,7 +1222,8 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap) wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_QUERY_FIRMWARE_CONFIG); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); @@ -1232,7 +1251,8 @@ int be_cmd_reset_function(struct be_adapter *adapter) wrb = wrb_from_mbox(adapter); req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_FUNCTION_RESET); be_cmd_hdr_prepare(req, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_FUNCTION_RESET, sizeof(*req)); @@ -1260,7 +1280,8 @@ int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_ENABLE_DISABLE_BEACON); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_ENABLE_DISABLE_BEACON, sizeof(*req)); @@ -1293,7 +1314,8 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num, u32 *state) } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_GET_BEACON_STATE); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_GET_BEACON_STATE, sizeof(*req)); @@ -1329,7 +1351,8 @@ int be_cmd_read_port_type(struct be_adapter *adapter, u32 port, } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(struct be_cmd_resp_port_type), true, 0); + be_wrb_hdr_prepare(wrb, sizeof(struct be_cmd_resp_port_type), true, 0, + OPCODE_COMMON_READ_TRANSRECV_DATA); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_READ_TRANSRECV_DATA, sizeof(*req)); @@ -1365,7 +1388,8 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, req = cmd->va; sge = nonembedded_sgl(wrb); - be_wrb_hdr_prepare(wrb, cmd->size, false, 1); + be_wrb_hdr_prepare(wrb, cmd->size, false, 1, + OPCODE_COMMON_WRITE_FLASHROM); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_WRITE_FLASHROM, cmd->size); @@ -1399,7 +1423,8 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc) } req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req)+4, true, 0); + be_wrb_hdr_prepare(wrb, sizeof(*req)+4, true, 0, + OPCODE_COMMON_READ_FLASHROM); be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_READ_FLASHROM, sizeof(*req)+4); @@ -1417,3 +1442,132 @@ err: spin_unlock_bh(&adapter->mcc_lock); return status; } + +extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, + struct be_dma_mem *nonemb_cmd) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_acpi_wol_magic_config *req; + struct be_sge *sge; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = nonemb_cmd->va; + sge = nonembedded_sgl(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1, + OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, + OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, sizeof(*req)); + memcpy(req->magic_mac, mac, ETH_ALEN); + + sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); + sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(nonemb_cmd->size); + + status = be_mcc_notify_wait(adapter); + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, + u32 loopback_type, u32 pkt_size, u32 num_pkts, u64 pattern) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_loopback_test *req; + int status; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_LOWLEVEL_LOOPBACK_TEST); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, + OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req)); + + req->pattern = cpu_to_le64(pattern); + req->src_port = cpu_to_le32(port_num); + req->dest_port = cpu_to_le32(port_num); + req->pkt_size = cpu_to_le32(pkt_size); + req->num_pkts = cpu_to_le32(num_pkts); + req->loopback_type = cpu_to_le32(loopback_type); + + status = be_mcc_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_loopback_test *resp = embedded_payload(wrb); + status = le32_to_cpu(resp->status); + } + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} + +int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, + u32 byte_cnt, struct be_dma_mem *cmd) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_ddrdma_test *req; + struct be_sge *sge; + int status; + int i, j = 0; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + req = cmd->va; + sge = nonembedded_sgl(wrb); + be_wrb_hdr_prepare(wrb, cmd->size, false, 1, + OPCODE_LOWLEVEL_HOST_DDR_DMA); + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL, + OPCODE_LOWLEVEL_HOST_DDR_DMA, cmd->size); + + sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma)); + sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF); + sge->len = cpu_to_le32(cmd->size); + + req->pattern = cpu_to_le64(pattern); + req->byte_count = cpu_to_le32(byte_cnt); + for (i = 0; i < byte_cnt; i++) { + req->snd_buff[i] = (u8)(pattern >> (j*8)); + j++; + if (j > 7) + j = 0; + } + + status = be_mcc_notify_wait(adapter); + + if (!status) { + struct be_cmd_resp_ddrdma_test *resp; + resp = cmd->va; + if ((memcmp(resp->rcv_buff, req->snd_buff, byte_cnt) != 0) || + resp->snd_err) { + status = -1; + } + } + +err: + spin_unlock_bh(&adapter->mcc_lock); + return status; +} diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 8ec6528cb05..e7323be507d 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -112,6 +112,7 @@ struct be_mcc_mailbox { #define CMD_SUBSYSTEM_COMMON 0x1 #define CMD_SUBSYSTEM_ETH 0x3 +#define CMD_SUBSYSTEM_LOWLEVEL 0xb #define OPCODE_COMMON_NTWK_MAC_QUERY 1 #define OPCODE_COMMON_NTWK_MAC_SET 2 @@ -150,6 +151,10 @@ struct be_mcc_mailbox { #define OPCODE_ETH_RX_CREATE 8 #define OPCODE_ETH_TX_DESTROY 9 #define OPCODE_ETH_RX_DESTROY 10 +#define OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG 12 + +#define OPCODE_LOWLEVEL_HOST_DDR_DMA 17 +#define OPCODE_LOWLEVEL_LOOPBACK_TEST 18 struct be_cmd_req_hdr { u8 opcode; /* dword 0 */ @@ -788,6 +793,53 @@ struct be_cmd_write_flashrom { struct flashrom_params params; }; +/************************ WOL *******************************/ +struct be_cmd_req_acpi_wol_magic_config{ + struct be_cmd_req_hdr hdr; + u32 rsvd0[145]; + u8 magic_mac[6]; + u8 rsvd2[2]; +} __packed; + +/********************** LoopBack test *********************/ +struct be_cmd_req_loopback_test { + struct be_cmd_req_hdr hdr; + u32 loopback_type; + u32 num_pkts; + u64 pattern; + u32 src_port; + u32 dest_port; + u32 pkt_size; +}; + +struct be_cmd_resp_loopback_test { + struct be_cmd_resp_hdr resp_hdr; + u32 status; + u32 num_txfer; + u32 num_rx; + u32 miscomp_off; + u32 ticks_compl; +}; + +/********************** DDR DMA test *********************/ +struct be_cmd_req_ddrdma_test { + struct be_cmd_req_hdr hdr; + u64 pattern; + u32 byte_count; + u32 rsvd0; + u8 snd_buff[4096]; + u8 rsvd1[4096]; +}; + +struct be_cmd_resp_ddrdma_test { + struct be_cmd_resp_hdr hdr; + u64 pattern; + u32 byte_cnt; + u32 snd_err; + u8 rsvd0[4096]; + u8 rcv_buff[4096]; +}; + extern int be_pci_fnum_get(struct be_adapter *adapter); extern int be_cmd_POST(struct be_adapter *adapter); extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, @@ -851,5 +903,12 @@ extern int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, u32 flash_oper, u32 flash_opcode, u32 buf_size); extern int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc); +extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac, + struct be_dma_mem *nonemb_cmd); extern int be_cmd_fw_init(struct be_adapter *adapter); extern int be_cmd_fw_clean(struct be_adapter *adapter); +extern int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, + u32 loopback_type, u32 pkt_size, + u32 num_pkts, u64 pattern); +extern int be_cmd_ddr_dma_test(struct be_adapter *adapter, u64 pattern, + u32 byte_cnt, struct be_dma_mem *cmd); diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c index e8f92831021..298b92cbd68 100644 --- a/drivers/net/benet/be_ethtool.c +++ b/drivers/net/benet/be_ethtool.c @@ -55,7 +55,7 @@ static const struct be_ethtool_stat et_stats[] = { {DRVSTAT_INFO(be_tx_stops)}, {DRVSTAT_INFO(be_fwd_reqs)}, {DRVSTAT_INFO(be_tx_wrbs)}, - {DRVSTAT_INFO(be_polls)}, + {DRVSTAT_INFO(be_rx_polls)}, {DRVSTAT_INFO(be_tx_events)}, {DRVSTAT_INFO(be_rx_events)}, {DRVSTAT_INFO(be_tx_compl)}, @@ -107,6 +107,18 @@ static const struct be_ethtool_stat et_stats[] = { }; #define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats) +static const char et_self_tests[][ETH_GSTRING_LEN] = { + "MAC Loopback test", + "PHY Loopback test", + "External Loopback test", + "DDR DMA test" +}; + +#define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests) +#define BE_MAC_LOOPBACK 0x0 +#define BE_PHY_LOOPBACK 0x1 +#define BE_ONE_PORT_EXT_LOOPBACK 0x2 + static void be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { @@ -278,12 +290,20 @@ be_get_stat_strings(struct net_device *netdev, uint32_t stringset, data += ETH_GSTRING_LEN; } break; + case ETH_SS_TEST: + for (i = 0; i < ETHTOOL_TESTS_NUM; i++) { + memcpy(data, et_self_tests[i], ETH_GSTRING_LEN); + data += ETH_GSTRING_LEN; + } + break; } } static int be_get_sset_count(struct net_device *netdev, int stringset) { switch (stringset) { + case ETH_SS_TEST: + return ETHTOOL_TESTS_NUM; case ETH_SS_STATS: return ETHTOOL_STATS_NUM; default: @@ -297,36 +317,48 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) u8 mac_speed = 0, connector = 0; u16 link_speed = 0; bool link_up = false; + int status; - be_cmd_link_status_query(adapter, &link_up, &mac_speed, &link_speed); + if (adapter->link_speed < 0) { + status = be_cmd_link_status_query(adapter, &link_up, + &mac_speed, &link_speed); + + /* link_speed is in units of 10 Mbps */ + if (link_speed) { + ecmd->speed = link_speed*10; + } else { + switch (mac_speed) { + case PHY_LINK_SPEED_1GBPS: + ecmd->speed = SPEED_1000; + break; + case PHY_LINK_SPEED_10GBPS: + ecmd->speed = SPEED_10000; + break; + } + } - /* link_speed is in units of 10 Mbps */ - if (link_speed) { - ecmd->speed = link_speed*10; - } else { - switch (mac_speed) { - case PHY_LINK_SPEED_1GBPS: - ecmd->speed = SPEED_1000; + status = be_cmd_read_port_type(adapter, adapter->port_num, + &connector); + switch (connector) { + case 7: + ecmd->port = PORT_FIBRE; break; - case PHY_LINK_SPEED_10GBPS: - ecmd->speed = SPEED_10000; + default: + ecmd->port = PORT_TP; break; } + + /* Save for future use */ + adapter->link_speed = ecmd->speed; + adapter->port_type = ecmd->port; + } else { + ecmd->speed = adapter->link_speed; + ecmd->port = adapter->port_type; } + ecmd->duplex = DUPLEX_FULL; ecmd->autoneg = AUTONEG_DISABLE; ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_TP); - - be_cmd_read_port_type(adapter, adapter->port_num, &connector); - switch (connector) { - case 7: - ecmd->port = PORT_FIBRE; - break; - default: - ecmd->port = PORT_TP; - break; - } - ecmd->phy_address = adapter->port_num; ecmd->transceiver = XCVR_INTERNAL; @@ -380,9 +412,6 @@ be_phys_id(struct net_device *netdev, u32 data) int status; u32 cur; - if (!netif_running(netdev)) - return 0; - be_cmd_get_beacon_state(adapter, adapter->port_num, &cur); if (cur == BEACON_STATE_ENABLED) @@ -402,6 +431,97 @@ be_phys_id(struct net_device *netdev, u32 data) return status; } +static void +be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct be_adapter *adapter = netdev_priv(netdev); + + wol->supported = WAKE_MAGIC; + if (adapter->wol) + wol->wolopts = WAKE_MAGIC; + else + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); + return; +} + +static int +be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +{ + struct be_adapter *adapter = netdev_priv(netdev); + + if (wol->wolopts & ~WAKE_MAGIC) + return -EINVAL; + + if (wol->wolopts & WAKE_MAGIC) + adapter->wol = true; + else + adapter->wol = false; + + return 0; +} + +static int +be_test_ddr_dma(struct be_adapter *adapter) +{ + int ret, i; + struct be_dma_mem ddrdma_cmd; + u64 pattern[2] = {0x5a5a5a5a5a5a5a5a, 0xa5a5a5a5a5a5a5a5}; + + ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test); + ddrdma_cmd.va = pci_alloc_consistent(adapter->pdev, ddrdma_cmd.size, + &ddrdma_cmd.dma); + if (!ddrdma_cmd.va) { + dev_err(&adapter->pdev->dev, "Memory allocation failure \n"); + return -ENOMEM; + } + + for (i = 0; i < 2; i++) { + ret = be_cmd_ddr_dma_test(adapter, pattern[i], + 4096, &ddrdma_cmd); + if (ret != 0) + goto err; + } + +err: + pci_free_consistent(adapter->pdev, ddrdma_cmd.size, + ddrdma_cmd.va, ddrdma_cmd.dma); + return ret; +} + +static void +be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) +{ + struct be_adapter *adapter = netdev_priv(netdev); + + memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM); + + if (test->flags & ETH_TEST_FL_OFFLINE) { + data[0] = be_cmd_loopback_test(adapter, adapter->port_num, + BE_MAC_LOOPBACK, 1500, + 2, 0xabc); + if (data[0] != 0) + test->flags |= ETH_TEST_FL_FAILED; + + data[1] = be_cmd_loopback_test(adapter, adapter->port_num, + BE_PHY_LOOPBACK, 1500, + 2, 0xabc); + if (data[1] != 0) + test->flags |= ETH_TEST_FL_FAILED; + + data[2] = be_cmd_loopback_test(adapter, adapter->port_num, + BE_ONE_PORT_EXT_LOOPBACK, + 1500, 2, 0xabc); + if (data[2] != 0) + test->flags |= ETH_TEST_FL_FAILED; + + data[3] = be_test_ddr_dma(adapter); + if (data[3] != 0) + test->flags |= ETH_TEST_FL_FAILED; + } + +} + static int be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) { @@ -419,6 +539,8 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl) const struct ethtool_ops be_ethtool_ops = { .get_settings = be_get_settings, .get_drvinfo = be_get_drvinfo, + .get_wol = be_get_wol, + .set_wol = be_set_wol, .get_link = ethtool_op_get_link, .get_coalesce = be_get_coalesce, .set_coalesce = be_set_coalesce, @@ -438,4 +560,5 @@ const struct ethtool_ops be_ethtool_ops = { .get_sset_count = be_get_sset_count, .get_ethtool_stats = be_get_ethtool_stats, .flash_device = be_do_flash, + .self_test = be_self_test, }; diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h index f53d5ca2da9..e2b3beffd49 100644 --- a/drivers/net/benet/be_hw.h +++ b/drivers/net/benet/be_hw.h @@ -52,6 +52,10 @@ */ #define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */ +/********* Power managment (WOL) **********/ +#define PCICFG_PM_CONTROL_OFFSET 0x44 +#define PCICFG_PM_CONTROL_MASK 0x108 /* bits 3 & 8 */ + /********* ISR0 Register offset **********/ #define CEV_ISR0_OFFSET 0xC18 #define CEV_ISR_SIZE 4 diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 79593643949..957a0f7f276 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -125,6 +125,9 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) struct sockaddr *addr = p; int status = 0; + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id); if (status) return status; @@ -217,6 +220,7 @@ void be_link_status_update(struct be_adapter *adapter, bool link_up) /* If link came up or went down */ if (adapter->link_up != link_up) { + adapter->link_speed = -1; if (link_up) { netif_start_queue(netdev); netif_carrier_on(netdev); @@ -390,15 +394,11 @@ static int make_tx_wrbs(struct be_adapter *adapter, atomic_add(wrb_cnt, &txq->used); queue_head_inc(txq); - if (skb_dma_map(&pdev->dev, skb, DMA_TO_DEVICE)) { - dev_err(&pdev->dev, "TX DMA mapping failed\n"); - return 0; - } - if (skb->len > skb->data_len) { int len = skb->len - skb->data_len; + busaddr = pci_map_single(pdev, skb->data, len, + PCI_DMA_TODEVICE); wrb = queue_head_node(txq); - busaddr = skb_shinfo(skb)->dma_head; wrb_fill(wrb, busaddr, len); be_dws_cpu_to_le(wrb, sizeof(*wrb)); queue_head_inc(txq); @@ -408,8 +408,9 @@ static int make_tx_wrbs(struct be_adapter *adapter, for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; - - busaddr = skb_shinfo(skb)->dma_maps[i]; + busaddr = pci_map_page(pdev, frag->page, + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, frag->size); be_dws_cpu_to_le(wrb, sizeof(*wrb)); @@ -982,23 +983,41 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) { struct be_queue_info *txq = &adapter->tx_obj.q; + struct be_eth_wrb *wrb; struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; struct sk_buff *sent_skb; + u64 busaddr; u16 cur_index, num_wrbs = 0; cur_index = txq->tail; sent_skb = sent_skbs[cur_index]; BUG_ON(!sent_skb); sent_skbs[cur_index] = NULL; + wrb = queue_tail_node(txq); + be_dws_le_to_cpu(wrb, sizeof(*wrb)); + busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo; + if (busaddr != 0) { + pci_unmap_single(adapter->pdev, busaddr, + wrb->frag_len, PCI_DMA_TODEVICE); + } + num_wrbs++; + queue_tail_inc(txq); - do { + while (cur_index != last_index) { cur_index = txq->tail; + wrb = queue_tail_node(txq); + be_dws_le_to_cpu(wrb, sizeof(*wrb)); + busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo; + if (busaddr != 0) { + pci_unmap_page(adapter->pdev, busaddr, + wrb->frag_len, PCI_DMA_TODEVICE); + } num_wrbs++; queue_tail_inc(txq); - } while (cur_index != last_index); + } atomic_sub(num_wrbs, &txq->used); - skb_dma_unmap(&adapter->pdev->dev, sent_skb, DMA_TO_DEVICE); + kfree_skb(sent_skb); } @@ -1378,6 +1397,7 @@ int be_poll_rx(struct napi_struct *napi, int budget) struct be_eth_rx_compl *rxcp; u32 work_done; + adapter->stats.drvr_stats.be_rx_polls++; for (work_done = 0; work_done < budget; work_done++) { rxcp = be_rx_compl_get(adapter); if (!rxcp) @@ -1639,6 +1659,44 @@ ret_sts: return status; } +static int be_setup_wol(struct be_adapter *adapter, bool enable) +{ + struct be_dma_mem cmd; + int status = 0; + u8 mac[ETH_ALEN]; + + memset(mac, 0, ETH_ALEN); + + cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config); + cmd.va = pci_alloc_consistent(adapter->pdev, cmd.size, &cmd.dma); + if (cmd.va == NULL) + return -1; + memset(cmd.va, 0, cmd.size); + + if (enable) { + status = pci_write_config_dword(adapter->pdev, + PCICFG_PM_CONTROL_OFFSET, PCICFG_PM_CONTROL_MASK); + if (status) { + dev_err(&adapter->pdev->dev, + "Could not enable Wake-on-lan \n"); + pci_free_consistent(adapter->pdev, cmd.size, cmd.va, + cmd.dma); + return status; + } + status = be_cmd_enable_magic_wol(adapter, + adapter->netdev->dev_addr, &cmd); + pci_enable_wake(adapter->pdev, PCI_D3hot, 1); + pci_enable_wake(adapter->pdev, PCI_D3cold, 1); + } else { + status = be_cmd_enable_magic_wol(adapter, mac, &cmd); + pci_enable_wake(adapter->pdev, PCI_D3hot, 0); + pci_enable_wake(adapter->pdev, PCI_D3cold, 0); + } + + pci_free_consistent(adapter->pdev, cmd.size, cmd.va, cmd.dma); + return status; +} + static int be_setup(struct be_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -1670,6 +1728,8 @@ static int be_setup(struct be_adapter *adapter) if (status != 0) goto rx_qs_destroy; + adapter->link_speed = -1; + return 0; rx_qs_destroy: @@ -1951,6 +2011,8 @@ static void be_netdev_init(struct net_device *netdev) NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM | NETIF_F_GRO; + netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM; + netdev->flags |= IFF_MULTICAST; adapter->rx_csum = true; @@ -2144,7 +2206,12 @@ static int be_get_config(struct be_adapter *adapter) MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0); if (status) return status; + + if (!is_valid_ether_addr(mac)) + return -EADDRNOTAVAIL; + memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); + memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); return 0; } @@ -2253,6 +2320,9 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) struct be_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; + if (adapter->wol) + be_setup_wol(adapter, true); + netif_device_detach(netdev); if (netif_running(netdev)) { rtnl_lock(); @@ -2295,6 +2365,9 @@ static int be_resume(struct pci_dev *pdev) rtnl_unlock(); } netif_device_attach(netdev); + + if (adapter->wol) + be_setup_wol(adapter, false); return 0; } @@ -2309,8 +2382,8 @@ static struct pci_driver be_driver = { static int __init be_init_module(void) { - if (rx_frag_size != 8192 && rx_frag_size != 4096 - && rx_frag_size != 2048) { + if (rx_frag_size != 8192 && rx_frag_size != 4096 && + rx_frag_size != 2048) { printk(KERN_WARNING DRV_NAME " : Module param rx_frag_size must be 2048/4096/8192." " Using 2048\n"); diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index 14bd3801f7d..8ffea3990d0 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -554,8 +554,8 @@ static void adjust_tx_list(void) { int timeout_cnt = MAX_TIMEOUT_CNT; - if (tx_list_head->status.status_word != 0 - && current_tx_ptr != tx_list_head) { + if (tx_list_head->status.status_word != 0 && + current_tx_ptr != tx_list_head) { goto adjust_head; /* released something, just return; */ } @@ -567,8 +567,8 @@ static void adjust_tx_list(void) if (current_tx_ptr->next->next == tx_list_head) { while (tx_list_head->status.status_word == 0) { udelay(10); - if (tx_list_head->status.status_word != 0 - || !(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN)) { + if (tx_list_head->status.status_word != 0 || + !(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN)) { goto adjust_head; } if (timeout_cnt-- < 0) { @@ -596,8 +596,8 @@ adjust_head: ": no sk_buff in a transmitted frame!\n"); } tx_list_head = tx_list_head->next; - } while (tx_list_head->status.status_word != 0 - && current_tx_ptr != tx_list_head); + } while (tx_list_head->status.status_word != 0 && + current_tx_ptr != tx_list_head); return; } diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 406f0642425..9b587c34419 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -438,8 +438,8 @@ bmac_init_phy(struct net_device *dev) ctrl = bmac_mif_read(dev, 0); capable = ((bmac_mif_read(dev, 1) & 0xf800) >> 6) | 1; - if (bmac_mif_read(dev, 4) != capable - || (ctrl & 0x1000) == 0) { + if (bmac_mif_read(dev, 4) != capable || + (ctrl & 0x1000) == 0) { bmac_mif_write(dev, 4, capable); bmac_mif_write(dev, 0, 0x1200); } else diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 539d23b594c..4bfc8081292 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -59,8 +59,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "2.0.2" -#define DRV_MODULE_RELDATE "Aug 21, 2009" +#define DRV_MODULE_VERSION "2.0.3" +#define DRV_MODULE_RELDATE "Dec 03, 2009" #define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-5.0.0.j3.fw" #define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-5.0.0.j3.fw" #define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-5.0.0.j3.fw" @@ -2815,13 +2815,21 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) } } - skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE); + pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping), + skb_headlen(skb), PCI_DMA_TODEVICE); tx_buf->skb = NULL; last = tx_buf->nr_frags; for (i = 0; i < last; i++) { sw_cons = NEXT_TX_BD(sw_cons); + + pci_unmap_page(bp->pdev, + pci_unmap_addr( + &txr->tx_buf_ring[TX_RING_IDX(sw_cons)], + mapping), + skb_shinfo(skb)->frags[i].size, + PCI_DMA_TODEVICE); } sw_cons = NEXT_TX_BD(sw_cons); @@ -5150,8 +5158,12 @@ bnx2_init_rx_ring(struct bnx2 *bp, int ring_num) ring_prod = prod = rxr->rx_pg_prod; for (i = 0; i < bp->rx_pg_ring_size; i++) { - if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0) + if (bnx2_alloc_rx_page(bp, rxr, ring_prod) < 0) { + printk(KERN_WARNING PFX "%s: init'ed rx page ring %d " + "with %d/%d pages only\n", + bp->dev->name, ring_num, i, bp->rx_pg_ring_size); break; + } prod = NEXT_RX_BD(prod); ring_prod = RX_PG_RING_IDX(prod); } @@ -5159,8 +5171,12 @@ bnx2_init_rx_ring(struct bnx2 *bp, int ring_num) ring_prod = prod = rxr->rx_prod; for (i = 0; i < bp->rx_ring_size; i++) { - if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0) + if (bnx2_alloc_rx_skb(bp, rxr, ring_prod) < 0) { + printk(KERN_WARNING PFX "%s: init'ed rx ring %d with " + "%d/%d skbs only\n", + bp->dev->name, ring_num, i, bp->rx_ring_size); break; + } prod = NEXT_RX_BD(prod); ring_prod = RX_RING_IDX(prod); } @@ -5295,17 +5311,29 @@ bnx2_free_tx_skbs(struct bnx2 *bp) for (j = 0; j < TX_DESC_CNT; ) { struct sw_tx_bd *tx_buf = &txr->tx_buf_ring[j]; struct sk_buff *skb = tx_buf->skb; + int k, last; if (skb == NULL) { j++; continue; } - skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE); + pci_unmap_single(bp->pdev, + pci_unmap_addr(tx_buf, mapping), + skb_headlen(skb), + PCI_DMA_TODEVICE); tx_buf->skb = NULL; - j += skb_shinfo(skb)->nr_frags + 1; + last = tx_buf->nr_frags; + j++; + for (k = 0; k < last; k++, j++) { + tx_buf = &txr->tx_buf_ring[TX_RING_IDX(j)]; + pci_unmap_page(bp->pdev, + pci_unmap_addr(tx_buf, mapping), + skb_shinfo(skb)->frags[k].size, + PCI_DMA_TODEVICE); + } dev_kfree_skb(skb); } } @@ -5684,11 +5712,12 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) for (i = 14; i < pkt_size; i++) packet[i] = (unsigned char) (i & 0xff); - if (skb_dma_map(&bp->pdev->dev, skb, DMA_TO_DEVICE)) { + map = pci_map_single(bp->pdev, skb->data, pkt_size, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(bp->pdev, map)) { dev_kfree_skb(skb); return -EIO; } - map = skb_shinfo(skb)->dma_head; REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); @@ -5723,7 +5752,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) udelay(5); - skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE); + pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE); dev_kfree_skb(skb); if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod) @@ -6242,8 +6271,11 @@ bnx2_reset_task(struct work_struct *work) { struct bnx2 *bp = container_of(work, struct bnx2, reset_task); - if (!netif_running(bp->dev)) + rtnl_lock(); + if (!netif_running(bp->dev)) { + rtnl_unlock(); return; + } bnx2_netif_stop(bp); @@ -6251,6 +6283,28 @@ bnx2_reset_task(struct work_struct *work) atomic_set(&bp->intr_sem, 1); bnx2_netif_start(bp); + rtnl_unlock(); +} + +static void +bnx2_dump_state(struct bnx2 *bp) +{ + struct net_device *dev = bp->dev; + + printk(KERN_ERR PFX "%s DEBUG: intr_sem[%x]\n", dev->name, + atomic_read(&bp->intr_sem)); + printk(KERN_ERR PFX "%s DEBUG: EMAC_TX_STATUS[%08x] " + "RPM_MGMT_PKT_CTRL[%08x]\n", dev->name, + REG_RD(bp, BNX2_EMAC_TX_STATUS), + REG_RD(bp, BNX2_RPM_MGMT_PKT_CTRL)); + printk(KERN_ERR PFX "%s DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n", + dev->name, bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P0), + bnx2_reg_rd_ind(bp, BNX2_MCP_STATE_P1)); + printk(KERN_ERR PFX "%s DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n", + dev->name, REG_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS)); + if (bp->flags & BNX2_FLAG_USING_MSIX) + printk(KERN_ERR PFX "%s DEBUG: PBA[%08x]\n", dev->name, + REG_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE)); } static void @@ -6258,6 +6312,8 @@ bnx2_tx_timeout(struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); + bnx2_dump_state(bp); + /* This allows the netif to be shutdown gracefully before resetting */ schedule_work(&bp->reset_task); } @@ -6302,7 +6358,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) struct bnx2_napi *bnapi; struct bnx2_tx_ring_info *txr; struct netdev_queue *txq; - struct skb_shared_info *sp; /* Determine which tx ring we will be placed on */ i = skb_get_queue_mapping(skb); @@ -6367,16 +6422,15 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) } else mss = 0; - if (skb_dma_map(&bp->pdev->dev, skb, DMA_TO_DEVICE)) { + mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(bp->pdev, mapping)) { dev_kfree_skb(skb); return NETDEV_TX_OK; } - sp = skb_shinfo(skb); - mapping = sp->dma_head; - tx_buf = &txr->tx_buf_ring[ring_prod]; tx_buf->skb = skb; + pci_unmap_addr_set(tx_buf, mapping, mapping); txbd = &txr->tx_desc_ring[ring_prod]; @@ -6397,7 +6451,12 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) txbd = &txr->tx_desc_ring[ring_prod]; len = frag->size; - mapping = sp->dma_maps[i]; + mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset, + len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(bp->pdev, mapping)) + goto dma_error; + pci_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping, + mapping); txbd->tx_bd_haddr_hi = (u64) mapping >> 32; txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff; @@ -6424,6 +6483,30 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) } return NETDEV_TX_OK; +dma_error: + /* save value of frag that failed */ + last_frag = i; + + /* start back at beginning and unmap skb */ + prod = txr->tx_prod; + ring_prod = TX_RING_IDX(prod); + tx_buf = &txr->tx_buf_ring[ring_prod]; + tx_buf->skb = NULL; + pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping), + skb_headlen(skb), PCI_DMA_TODEVICE); + + /* unmap remaining mapped pages */ + for (i = 0; i < last_frag; i++) { + prod = NEXT_TX_BD(prod); + ring_prod = TX_RING_IDX(prod); + tx_buf = &txr->tx_buf_ring[ring_prod]; + pci_unmap_page(bp->pdev, pci_unmap_addr(tx_buf, mapping), + skb_shinfo(skb)->frags[i].size, + PCI_DMA_TODEVICE); + } + + dev_kfree_skb(skb); + return NETDEV_TX_OK; } /* Called with rtnl_lock */ @@ -7639,6 +7722,86 @@ bnx2_get_pci_speed(struct bnx2 *bp) } +static void __devinit +bnx2_read_vpd_fw_ver(struct bnx2 *bp) +{ + int rc, i, v0_len = 0; + u8 *data; + u8 *v0_str = NULL; + bool mn_match = false; + +#define BNX2_VPD_NVRAM_OFFSET 0x300 +#define BNX2_VPD_LEN 128 +#define BNX2_MAX_VER_SLEN 30 + + data = kmalloc(256, GFP_KERNEL); + if (!data) + return; + + rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN, + BNX2_VPD_LEN); + if (rc) + goto vpd_done; + + for (i = 0; i < BNX2_VPD_LEN; i += 4) { + data[i] = data[i + BNX2_VPD_LEN + 3]; + data[i + 1] = data[i + BNX2_VPD_LEN + 2]; + data[i + 2] = data[i + BNX2_VPD_LEN + 1]; + data[i + 3] = data[i + BNX2_VPD_LEN]; + } + + for (i = 0; i <= BNX2_VPD_LEN - 3; ) { + unsigned char val = data[i]; + unsigned int block_end; + + if (val == 0x82 || val == 0x91) { + i = (i + 3 + (data[i + 1] + (data[i + 2] << 8))); + continue; + } + + if (val != 0x90) + goto vpd_done; + + block_end = (i + 3 + (data[i + 1] + (data[i + 2] << 8))); + i += 3; + + if (block_end > BNX2_VPD_LEN) + goto vpd_done; + + while (i < (block_end - 2)) { + int len = data[i + 2]; + + if (i + 3 + len > block_end) + goto vpd_done; + + if (data[i] == 'M' && data[i + 1] == 'N') { + if (len != 4 || + memcmp(&data[i + 3], "1028", 4)) + goto vpd_done; + mn_match = true; + + } else if (data[i] == 'V' && data[i + 1] == '0') { + if (len > BNX2_MAX_VER_SLEN) + goto vpd_done; + + v0_len = len; + v0_str = &data[i + 3]; + } + i += 3 + len; + + if (mn_match && v0_str) { + memcpy(bp->fw_version, v0_str, v0_len); + bp->fw_version[v0_len] = ' '; + goto vpd_done; + } + } + goto vpd_done; + } + +vpd_done: + kfree(data); +} + static int __devinit bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) { @@ -7812,10 +7975,18 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) goto err_out_unmap; } + bnx2_read_vpd_fw_ver(bp); + + j = strlen(bp->fw_version); reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV); - for (i = 0, j = 0; i < 3; i++) { + for (i = 0; i < 3 && j < 24; i++) { u8 num, k, skip0; + if (i == 0) { + bp->fw_version[j++] = 'b'; + bp->fw_version[j++] = 'c'; + bp->fw_version[j++] = ' '; + } num = (u8) (reg >> (24 - (i * 8))); for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) { if (num >= k || !skip0 || k == 1) { @@ -7846,8 +8017,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) reg != BNX2_CONDITION_MFW_RUN_NONE) { u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR); - bp->fw_version[j++] = ' '; - for (i = 0; i < 3; i++) { + if (j < 32) + bp->fw_version[j++] = ' '; + for (i = 0; i < 3 && j < 28; i++) { reg = bnx2_reg_rd_ind(bp, addr + i * 4); reg = swab32(reg); memcpy(&bp->fw_version[j], ®, 4); @@ -8268,6 +8440,7 @@ static pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev) } pci_set_master(pdev); pci_restore_state(pdev); + pci_save_state(pdev); if (netif_running(dev)) { bnx2_set_power_state(bp, PCI_D0); diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index a4d83409f20..939dc44d50a 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6345,6 +6345,8 @@ struct l2_fhdr { #define BNX2_MCP_ROM 0x00150000 #define BNX2_MCP_SCRATCH 0x00160000 +#define BNX2_MCP_STATE_P1 0x0016f9c8 +#define BNX2_MCP_STATE_P0 0x0016fdc8 #define BNX2_SHM_HDR_SIGNATURE BNX2_MCP_SCRATCH #define BNX2_SHM_HDR_SIGNATURE_SIG_MASK 0xffff0000 @@ -6559,6 +6561,7 @@ struct sw_pg { struct sw_tx_bd { struct sk_buff *skb; + DECLARE_PCI_UNMAP_ADDR(mapping) unsigned short is_gso; unsigned short nr_frags; }; diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 41b9b7bd3d8..cf5778919b4 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -4717,8 +4717,8 @@ static u8 bnx2x_ext_phy_is_link_up(struct link_params *params, 0xc809, &val1); DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1); - ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) - && ((val1 & (1<<8)) == 0)); + ext_phy_link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && + ((val1 & (1<<8)) == 0)); if (ext_phy_link_up) vars->line_speed = SPEED_10000; break; diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 88c3fe80b35..d69e6838f21 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -561,12 +561,12 @@ static void __update_selected(struct lacpdu *lacpdu, struct port *port) const struct port_params *partner = &port->partner_oper; // check if any parameter is different - if (ntohs(lacpdu->actor_port) != partner->port_number - || ntohs(lacpdu->actor_port_priority) != partner->port_priority - || MAC_ADDRESS_COMPARE(&lacpdu->actor_system, &partner->system) - || ntohs(lacpdu->actor_system_priority) != partner->system_priority - || ntohs(lacpdu->actor_key) != partner->key - || (lacpdu->actor_state & AD_STATE_AGGREGATION) != (partner->port_state & AD_STATE_AGGREGATION)) { + if (ntohs(lacpdu->actor_port) != partner->port_number || + ntohs(lacpdu->actor_port_priority) != partner->port_priority || + MAC_ADDRESS_COMPARE(&lacpdu->actor_system, &partner->system) || + ntohs(lacpdu->actor_system_priority) != partner->system_priority || + ntohs(lacpdu->actor_key) != partner->key || + (lacpdu->actor_state & AD_STATE_AGGREGATION) != (partner->port_state & AD_STATE_AGGREGATION)) { // update the state machine Selected variable port->sm_vars &= ~AD_PORT_SELECTED; } @@ -592,12 +592,12 @@ static void __update_default_selected(struct port *port) const struct port_params *oper = &port->partner_oper; // check if any parameter is different - if (admin->port_number != oper->port_number - || admin->port_priority != oper->port_priority - || MAC_ADDRESS_COMPARE(&admin->system, &oper->system) - || admin->system_priority != oper->system_priority - || admin->key != oper->key - || (admin->port_state & AD_STATE_AGGREGATION) + if (admin->port_number != oper->port_number || + admin->port_priority != oper->port_priority || + MAC_ADDRESS_COMPARE(&admin->system, &oper->system) || + admin->system_priority != oper->system_priority || + admin->key != oper->key || + (admin->port_state & AD_STATE_AGGREGATION) != (oper->port_state & AD_STATE_AGGREGATION)) { // update the state machine Selected variable port->sm_vars &= ~AD_PORT_SELECTED; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 726bd755338..af9b9c4eb49 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1852,8 +1852,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) } if (!bond->params.fail_over_mac) { - if (!compare_ether_addr(bond_dev->dev_addr, slave->perm_hwaddr) - && bond->slave_cnt > 1) + if (!compare_ether_addr(bond_dev->dev_addr, slave->perm_hwaddr) && + bond->slave_cnt > 1) pr_warning(DRV_NAME ": %s: Warning: the permanent HWaddr of %s - " "%pM - is still in use by %s. " @@ -5103,42 +5103,28 @@ out_netdev: static int bond_net_init(struct net *net) { - struct bond_net *bn; - int err; - - err = -ENOMEM; - bn = kzalloc(sizeof(struct bond_net), GFP_KERNEL); - if (bn == NULL) - goto out; + struct bond_net *bn = net_generic(net, bond_net_id); bn->net = net; INIT_LIST_HEAD(&bn->dev_list); - err = net_assign_generic(net, bond_net_id, bn); - if (err) - goto out_free; - bond_create_proc_dir(bn); -out: - return err; -out_free: - kfree(bn); - goto out; + + return 0; } static void bond_net_exit(struct net *net) { - struct bond_net *bn; - - bn = net_generic(net, bond_net_id); + struct bond_net *bn = net_generic(net, bond_net_id); bond_destroy_proc_dir(bn); - kfree(bn); } static struct pernet_operations bond_net_ops = { .init = bond_net_init, .exit = bond_net_exit, + .id = &bond_net_id, + .size = sizeof(struct bond_net), }; static int __init bonding_init(void) @@ -5152,7 +5138,7 @@ static int __init bonding_init(void) if (res) goto out; - res = register_pernet_gen_subsys(&bond_net_id, &bond_net_ops); + res = register_pernet_subsys(&bond_net_ops); if (res) goto out; @@ -5178,7 +5164,7 @@ out: err: rtnl_link_unregister(&bond_link_ops); err_link: - unregister_pernet_gen_subsys(bond_net_id, &bond_net_ops); + unregister_pernet_subsys(&bond_net_ops); goto out; } @@ -5192,7 +5178,7 @@ static void __exit bonding_exit(void) bond_destroy_sysfs(); rtnl_link_unregister(&bond_link_ops); - unregister_pernet_gen_subsys(bond_net_id, &bond_net_ops); + unregister_pernet_subsys(&bond_net_ops); } module_init(bonding_init); diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a51ae7dc8d5..558ec135252 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -254,8 +254,8 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) static inline bool bond_is_lb(const struct bonding *bond) { - return bond->params.mode == BOND_MODE_TLB - || bond->params.mode == BOND_MODE_ALB; + return (bond->params.mode == BOND_MODE_TLB || + bond->params.mode == BOND_MODE_ALB); } #define BOND_PRI_RESELECT_ALWAYS 0 diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 3e4419054c8..591eb0eb1c2 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -318,12 +318,12 @@ static void ems_usb_rx_can_msg(struct ems_usb *dev, struct ems_cpc_msg *msg) cf->can_id = le32_to_cpu(msg->msg.can_msg.id); cf->can_dlc = min_t(u8, msg->msg.can_msg.length, 8); - if (msg->type == CPC_MSG_TYPE_EXT_CAN_FRAME - || msg->type == CPC_MSG_TYPE_EXT_RTR_FRAME) + if (msg->type == CPC_MSG_TYPE_EXT_CAN_FRAME || + msg->type == CPC_MSG_TYPE_EXT_RTR_FRAME) cf->can_id |= CAN_EFF_FLAG; - if (msg->type == CPC_MSG_TYPE_RTR_FRAME - || msg->type == CPC_MSG_TYPE_EXT_RTR_FRAME) { + if (msg->type == CPC_MSG_TYPE_RTR_FRAME || + msg->type == CPC_MSG_TYPE_EXT_RTR_FRAME) { cf->can_id |= CAN_RTR_FLAG; } else { for (i = 0; i < cf->can_dlc; i++) diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c index ee7eb9ee77e..d4c6e7fcff5 100644 --- a/drivers/net/cnic.c +++ b/drivers/net/cnic.c @@ -667,14 +667,14 @@ static void cnic_free_dma(struct cnic_dev *dev, struct cnic_dma *dma) for (i = 0; i < dma->num_pages; i++) { if (dma->pg_arr[i]) { - pci_free_consistent(dev->pcidev, BCM_PAGE_SIZE, - dma->pg_arr[i], dma->pg_map_arr[i]); + dma_free_coherent(&dev->pcidev->dev, BCM_PAGE_SIZE, + dma->pg_arr[i], dma->pg_map_arr[i]); dma->pg_arr[i] = NULL; } } if (dma->pgtbl) { - pci_free_consistent(dev->pcidev, dma->pgtbl_size, - dma->pgtbl, dma->pgtbl_map); + dma_free_coherent(&dev->pcidev->dev, dma->pgtbl_size, + dma->pgtbl, dma->pgtbl_map); dma->pgtbl = NULL; } kfree(dma->pg_arr); @@ -725,9 +725,10 @@ static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma, dma->num_pages = pages; for (i = 0; i < pages; i++) { - dma->pg_arr[i] = pci_alloc_consistent(dev->pcidev, - BCM_PAGE_SIZE, - &dma->pg_map_arr[i]); + dma->pg_arr[i] = dma_alloc_coherent(&dev->pcidev->dev, + BCM_PAGE_SIZE, + &dma->pg_map_arr[i], + GFP_ATOMIC); if (dma->pg_arr[i] == NULL) goto error; } @@ -736,8 +737,8 @@ static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma, dma->pgtbl_size = ((pages * 8) + BCM_PAGE_SIZE - 1) & ~(BCM_PAGE_SIZE - 1); - dma->pgtbl = pci_alloc_consistent(dev->pcidev, dma->pgtbl_size, - &dma->pgtbl_map); + dma->pgtbl = dma_alloc_coherent(&dev->pcidev->dev, dma->pgtbl_size, + &dma->pgtbl_map, GFP_ATOMIC); if (dma->pgtbl == NULL) goto error; @@ -757,9 +758,9 @@ static void cnic_free_context(struct cnic_dev *dev) for (i = 0; i < cp->ctx_blks; i++) { if (cp->ctx_arr[i].ctx) { - pci_free_consistent(dev->pcidev, cp->ctx_blk_size, - cp->ctx_arr[i].ctx, - cp->ctx_arr[i].mapping); + dma_free_coherent(&dev->pcidev->dev, cp->ctx_blk_size, + cp->ctx_arr[i].ctx, + cp->ctx_arr[i].mapping); cp->ctx_arr[i].ctx = NULL; } } @@ -781,14 +782,14 @@ static void cnic_free_resc(struct cnic_dev *dev) } if (cp->l2_buf) { - pci_free_consistent(dev->pcidev, cp->l2_buf_size, - cp->l2_buf, cp->l2_buf_map); + dma_free_coherent(&dev->pcidev->dev, cp->l2_buf_size, + cp->l2_buf, cp->l2_buf_map); cp->l2_buf = NULL; } if (cp->l2_ring) { - pci_free_consistent(dev->pcidev, cp->l2_ring_size, - cp->l2_ring, cp->l2_ring_map); + dma_free_coherent(&dev->pcidev->dev, cp->l2_ring_size, + cp->l2_ring, cp->l2_ring_map); cp->l2_ring = NULL; } @@ -849,8 +850,10 @@ static int cnic_alloc_context(struct cnic_dev *dev) for (i = 0; i < cp->ctx_blks; i++) { cp->ctx_arr[i].ctx = - pci_alloc_consistent(dev->pcidev, BCM_PAGE_SIZE, - &cp->ctx_arr[i].mapping); + dma_alloc_coherent(&dev->pcidev->dev, + BCM_PAGE_SIZE, + &cp->ctx_arr[i].mapping, + GFP_KERNEL); if (cp->ctx_arr[i].ctx == NULL) return -ENOMEM; } @@ -863,15 +866,17 @@ static int cnic_alloc_l2_rings(struct cnic_dev *dev, int pages) struct cnic_local *cp = dev->cnic_priv; cp->l2_ring_size = pages * BCM_PAGE_SIZE; - cp->l2_ring = pci_alloc_consistent(dev->pcidev, cp->l2_ring_size, - &cp->l2_ring_map); + cp->l2_ring = dma_alloc_coherent(&dev->pcidev->dev, cp->l2_ring_size, + &cp->l2_ring_map, + GFP_KERNEL | __GFP_COMP); if (!cp->l2_ring) return -ENOMEM; cp->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size; cp->l2_buf_size = PAGE_ALIGN(cp->l2_buf_size); - cp->l2_buf = pci_alloc_consistent(dev->pcidev, cp->l2_buf_size, - &cp->l2_buf_map); + cp->l2_buf = dma_alloc_coherent(&dev->pcidev->dev, cp->l2_buf_size, + &cp->l2_buf_map, + GFP_KERNEL | __GFP_COMP); if (!cp->l2_buf) return -ENOMEM; @@ -1006,8 +1011,9 @@ static int cnic_alloc_bnx2x_context(struct cnic_dev *dev) for (i = 0; i < blks; i++) { cp->ctx_arr[i].ctx = - pci_alloc_consistent(dev->pcidev, cp->ctx_blk_size, - &cp->ctx_arr[i].mapping); + dma_alloc_coherent(&dev->pcidev->dev, cp->ctx_blk_size, + &cp->ctx_arr[i].mapping, + GFP_KERNEL); if (cp->ctx_arr[i].ctx == NULL) return -ENOMEM; @@ -1500,9 +1506,9 @@ static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[], ictx->timers_context.flags |= ISCSI_TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG; ictx->ustorm_st_context.ring.rq.pbl_base.lo = - req2->rq_page_table_addr_lo & 0xffffffff; + req2->rq_page_table_addr_lo; ictx->ustorm_st_context.ring.rq.pbl_base.hi = - (u64) req2->rq_page_table_addr_hi >> 32; + req2->rq_page_table_addr_hi; ictx->ustorm_st_context.ring.rq.curr_pbe.lo = req3->qp_first_pte[0].hi; ictx->ustorm_st_context.ring.rq.curr_pbe.hi = req3->qp_first_pte[0].lo; ictx->ustorm_st_context.ring.r2tq.pbl_base.lo = @@ -3997,15 +4003,19 @@ static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev) if (base < 0xa0000 || base >= 0xc0000) return; - val = BNX2X_SHMEM_ADDR(base, + addr = BNX2X_SHMEM_ADDR(base, dev_info.port_hw_config[port].iscsi_mac_upper); + val = CNIC_RD(dev, addr); + dev->mac_addr[0] = (u8) (val >> 8); dev->mac_addr[1] = (u8) val; - val = BNX2X_SHMEM_ADDR(base, + addr = BNX2X_SHMEM_ADDR(base, dev_info.port_hw_config[port].iscsi_mac_lower); + val = CNIC_RD(dev, addr); + dev->mac_addr[2] = (u8) (val >> 24); dev->mac_addr[3] = (u8) (val >> 16); dev->mac_addr[4] = (u8) (val >> 8); @@ -4131,22 +4141,20 @@ static void cnic_init_rings(struct cnic_dev *dev) cnic_init_bnx2_rx_ring(dev); } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) { struct cnic_local *cp = dev->cnic_priv; - struct cnic_eth_dev *ethdev = cp->ethdev; u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp)); union l5cm_specific_data l5_data; struct ustorm_eth_rx_producers rx_prods = {0}; - void __iomem *doorbell; - int i; + u32 off, i; rx_prods.bd_prod = 0; rx_prods.cqe_prod = BNX2X_MAX_RCQ_DESC_CNT; barrier(); - doorbell = ethdev->io_base2 + BAR_USTRORM_INTMEM + + off = BAR_USTRORM_INTMEM + USTORM_RX_PRODS_OFFSET(CNIC_PORT(cp), cli); for (i = 0; i < sizeof(struct ustorm_eth_rx_producers) / 4; i++) - writel(((u32 *) &rx_prods)[i], doorbell + i * 4); + CNIC_WR(dev, off + i * 4, ((u32 *) &rx_prods)[i]); cnic_init_bnx2x_tx_ring(dev); cnic_init_bnx2x_rx_ring(dev); @@ -4166,8 +4174,15 @@ static void cnic_shutdown_rings(struct cnic_dev *dev) } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) { struct cnic_local *cp = dev->cnic_priv; u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp)); + union l5cm_specific_data l5_data; cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 0); + + l5_data.phy_address.lo = cli; + l5_data.phy_address.hi = 0; + cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_HALT, + BNX2X_ISCSI_L2_CID, ETH_CONNECTION_TYPE, &l5_data); + msleep(10); } } diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index b1a5a00a78c..cef3f882e2b 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -2117,19 +2117,19 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) if (t.qset_idx >= SGE_QSETS) return -EINVAL; if (!in_range(t.intr_lat, 0, M_NEWTIMER) || - !in_range(t.cong_thres, 0, 255) || - !in_range(t.txq_size[0], MIN_TXQ_ENTRIES, - MAX_TXQ_ENTRIES) || - !in_range(t.txq_size[1], MIN_TXQ_ENTRIES, - MAX_TXQ_ENTRIES) || - !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES, - MAX_CTRL_TXQ_ENTRIES) || - !in_range(t.fl_size[0], MIN_FL_ENTRIES, - MAX_RX_BUFFERS) - || !in_range(t.fl_size[1], MIN_FL_ENTRIES, - MAX_RX_JUMBO_BUFFERS) - || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES, - MAX_RSPQ_ENTRIES)) + !in_range(t.cong_thres, 0, 255) || + !in_range(t.txq_size[0], MIN_TXQ_ENTRIES, + MAX_TXQ_ENTRIES) || + !in_range(t.txq_size[1], MIN_TXQ_ENTRIES, + MAX_TXQ_ENTRIES) || + !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES, + MAX_CTRL_TXQ_ENTRIES) || + !in_range(t.fl_size[0], MIN_FL_ENTRIES, + MAX_RX_BUFFERS) || + !in_range(t.fl_size[1], MIN_FL_ENTRIES, + MAX_RX_JUMBO_BUFFERS) || + !in_range(t.rspq_size, MIN_RSPQ_ENTRIES, + MAX_RSPQ_ENTRIES)) return -EINVAL; if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0) diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index a2f1860fdd1..2a8b6a7c0b8 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -163,8 +163,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) strcmp (media[card_idx], "4") == 0) { np->speed = 100; np->full_duplex = 1; - } else if (strcmp (media[card_idx], "100mbps_hd") == 0 - || strcmp (media[card_idx], "3") == 0) { + } else if (strcmp (media[card_idx], "100mbps_hd") == 0 || + strcmp (media[card_idx], "3") == 0) { np->speed = 100; np->full_duplex = 0; } else if (strcmp (media[card_idx], "10mbps_fd") == 0 || diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 81590fbb994..0cbe3c0e7c0 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1024,8 +1024,8 @@ dm9000_rx(struct net_device *dev) } /* Move data from DM9000 */ - if (GoodPacket - && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { + if (GoodPacket && + ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { skb_reserve(skb, 2); rdptr = (u8 *) skb_put(skb, RxLen - 4); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index a81c7b0c41b..929701ca07d 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -157,6 +157,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/dma-mapping.h> +#include <linux/dmapool.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/mii.h> @@ -602,6 +603,7 @@ struct nic { struct mem *mem; dma_addr_t dma_addr; + struct pci_pool *cbs_pool; dma_addr_t cbs_dma_addr; u8 adaptive_ifs; u8 tx_threshold; @@ -1805,9 +1807,7 @@ static void e100_clean_cbs(struct nic *nic) nic->cb_to_clean = nic->cb_to_clean->next; nic->cbs_avail++; } - pci_free_consistent(nic->pdev, - sizeof(struct cb) * nic->params.cbs.count, - nic->cbs, nic->cbs_dma_addr); + pci_pool_free(nic->cbs_pool, nic->cbs, nic->cbs_dma_addr); nic->cbs = NULL; nic->cbs_avail = 0; } @@ -1825,8 +1825,8 @@ static int e100_alloc_cbs(struct nic *nic) nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL; nic->cbs_avail = 0; - nic->cbs = pci_alloc_consistent(nic->pdev, - sizeof(struct cb) * count, &nic->cbs_dma_addr); + nic->cbs = pci_pool_alloc(nic->cbs_pool, GFP_KERNEL, + &nic->cbs_dma_addr); if (!nic->cbs) return -ENOMEM; @@ -2852,7 +2852,11 @@ static int __devinit e100_probe(struct pci_dev *pdev, DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n"); goto err_out_free; } - + nic->cbs_pool = pci_pool_create(netdev->name, + nic->pdev, + nic->params.cbs.count * sizeof(struct cb), + sizeof(u32), + 0); DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n", (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq, netdev->dev_addr); @@ -2882,6 +2886,7 @@ static void __devexit e100_remove(struct pci_dev *pdev) unregister_netdev(netdev); e100_free(nic); pci_iounmap(pdev, nic->csr); + pci_pool_destroy(nic->cbs_pool); free_netdev(netdev); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index a5665287bd6..2a567df3ea7 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -167,6 +167,7 @@ struct e1000_buffer { unsigned long time_stamp; u16 length; u16 next_to_watch; + u16 mapped_as_page; }; struct e1000_tx_ring { diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index c938114a34a..7e855f9bbd9 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1839,10 +1839,17 @@ void e1000_free_all_tx_resources(struct e1000_adapter *adapter) static void e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info) { - buffer_info->dma = 0; + if (buffer_info->dma) { + if (buffer_info->mapped_as_page) + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + else + pci_unmap_single(adapter->pdev, buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } if (buffer_info->skb) { - skb_dma_unmap(&adapter->pdev->dev, buffer_info->skb, - DMA_TO_DEVICE); dev_kfree_skb_any(buffer_info->skb); buffer_info->skb = NULL; } @@ -2683,22 +2690,14 @@ static int e1000_tx_map(struct e1000_adapter *adapter, unsigned int mss) { struct e1000_hw *hw = &adapter->hw; + struct pci_dev *pdev = adapter->pdev; struct e1000_buffer *buffer_info; unsigned int len = skb_headlen(skb); - unsigned int offset, size, count = 0, i; + unsigned int offset = 0, size, count = 0, i; unsigned int f; - dma_addr_t *map; i = tx_ring->next_to_use; - if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) { - dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); - return 0; - } - - map = skb_shinfo(skb)->dma_maps; - offset = 0; - while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, max_per_txd); @@ -2735,7 +2734,11 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; - buffer_info->dma = skb_shinfo(skb)->dma_head + offset; + buffer_info->mapped_as_page = false; + buffer_info->dma = pci_map_single(pdev, skb->data + offset, + size, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) + goto dma_error; buffer_info->next_to_watch = i; len -= size; @@ -2753,7 +2756,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, frag = &skb_shinfo(skb)->frags[f]; len = frag->size; - offset = 0; + offset = frag->page_offset; while (len) { i++; @@ -2777,7 +2780,12 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; buffer_info->time_stamp = jiffies; - buffer_info->dma = map[f] + offset; + buffer_info->mapped_as_page = true; + buffer_info->dma = pci_map_page(pdev, frag->page, + offset, size, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) + goto dma_error; buffer_info->next_to_watch = i; len -= size; @@ -2790,6 +2798,22 @@ static int e1000_tx_map(struct e1000_adapter *adapter, tx_ring->buffer_info[first].next_to_watch = i; return count; + +dma_error: + dev_err(&pdev->dev, "TX DMA map failed\n"); + buffer_info->dma = 0; + count--; + + while (count >= 0) { + count--; + i--; + if (i < 0) + i += tx_ring->count; + buffer_info = &tx_ring->buffer_info[i]; + e1000_unmap_and_free_tx_resource(adapter, buffer_info); + } + + return 0; } static void e1000_tx_queue(struct e1000_adapter *adapter, @@ -3483,8 +3507,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter, adapter->detect_tx_hung = false; if (tx_ring->buffer_info[eop].time_stamp && time_after(jiffies, tx_ring->buffer_info[eop].time_stamp + - (adapter->tx_timeout_factor * HZ)) - && !(er32(STATUS) & E1000_STATUS_TXOFF)) { + (adapter->tx_timeout_factor * HZ)) && + !(er32(STATUS) & E1000_STATUS_TXOFF)) { /* detected Tx unit hang */ DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n" diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index 62bbc6e0a76..c1a42cfc80b 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -65,9 +65,11 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw); static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw); static s32 e1000_setup_link_82571(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw); +static void e1000_clear_vfta_82571(struct e1000_hw *hw); static bool e1000_check_mng_mode_82574(struct e1000_hw *hw); static s32 e1000_led_on_82574(struct e1000_hw *hw); static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw); +static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw); /** * e1000_init_phy_params_82571 - Init PHY func ptrs. @@ -87,6 +89,9 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw) phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; phy->reset_delay_us = 100; + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_82571; + switch (hw->mac.type) { case e1000_82571: case e1000_82572: @@ -949,7 +954,7 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw) /* Disabling VLAN filtering */ e_dbg("Initializing the IEEE VLAN\n"); - e1000e_clear_vfta(hw); + mac->ops.clear_vfta(hw); /* Setup the receive address. */ /* @@ -1128,13 +1133,13 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) } /** - * e1000e_clear_vfta - Clear VLAN filter table + * e1000_clear_vfta_82571 - Clear VLAN filter table * @hw: pointer to the HW structure * * Clears the register array which contains the VLAN filter table by * setting all the values to 0. **/ -void e1000e_clear_vfta(struct e1000_hw *hw) +static void e1000_clear_vfta_82571(struct e1000_hw *hw) { u32 offset; u32 vfta_value = 0; @@ -1351,8 +1356,20 @@ static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw) * e1000_check_for_serdes_link_82571 - Check for link (Serdes) * @hw: pointer to the HW structure * - * Checks for link up on the hardware. If link is not up and we have - * a signal, then we need to force link up. + * Reports the link state as up or down. + * + * If autonegotiation is supported by the link partner, the link state is + * determined by the result of autonegotiation. This is the most likely case. + * If autonegotiation is not supported by the link partner, and the link + * has a valid signal, force the link up. + * + * The link state is represented internally here by 4 states: + * + * 1) down + * 2) autoneg_progress + * 3) autoneg_complete (the link sucessfully autonegotiated) + * 4) forced_up (the link has been forced up, it did not autonegotiate) + * **/ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) { @@ -1378,6 +1395,7 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) */ mac->serdes_link_state = e1000_serdes_link_autoneg_progress; + mac->serdes_has_link = false; e_dbg("AN_UP -> AN_PROG\n"); } break; @@ -1392,57 +1410,64 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) if (rxcw & E1000_RXCW_C) { /* Enable autoneg, and unforce link up */ ew32(TXCW, mac->txcw); - ew32(CTRL, - (ctrl & ~E1000_CTRL_SLU)); + ew32(CTRL, (ctrl & ~E1000_CTRL_SLU)); mac->serdes_link_state = e1000_serdes_link_autoneg_progress; + mac->serdes_has_link = false; e_dbg("FORCED_UP -> AN_PROG\n"); } break; case e1000_serdes_link_autoneg_progress: - /* - * If the LU bit is set in the STATUS register, - * autoneg has completed sucessfully. If not, - * try foring the link because the far end may be - * available but not capable of autonegotiation. - */ - if (status & E1000_STATUS_LU) { - mac->serdes_link_state = - e1000_serdes_link_autoneg_complete; - e_dbg("AN_PROG -> AN_UP\n"); + if (rxcw & E1000_RXCW_C) { + /* + * We received /C/ ordered sets, meaning the + * link partner has autonegotiated, and we can + * trust the Link Up (LU) status bit. + */ + if (status & E1000_STATUS_LU) { + mac->serdes_link_state = + e1000_serdes_link_autoneg_complete; + e_dbg("AN_PROG -> AN_UP\n"); + mac->serdes_has_link = true; + } else { + /* Autoneg completed, but failed. */ + mac->serdes_link_state = + e1000_serdes_link_down; + e_dbg("AN_PROG -> DOWN\n"); + } } else { /* - * Disable autoneg, force link up and - * full duplex, and change state to forced + * The link partner did not autoneg. + * Force link up and full duplex, and change + * state to forced. */ - ew32(TXCW, - (mac->txcw & ~E1000_TXCW_ANE)); + ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE)); ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); ew32(CTRL, ctrl); /* Configure Flow Control after link up. */ - ret_val = - e1000e_config_fc_after_link_up(hw); + ret_val = e1000e_config_fc_after_link_up(hw); if (ret_val) { e_dbg("Error config flow control\n"); break; } mac->serdes_link_state = e1000_serdes_link_forced_up; + mac->serdes_has_link = true; e_dbg("AN_PROG -> FORCED_UP\n"); } - mac->serdes_has_link = true; break; case e1000_serdes_link_down: default: - /* The link was down but the receiver has now gained + /* + * The link was down but the receiver has now gained * valid sync, so lets see if we can bring the link - * up. */ + * up. + */ ew32(TXCW, mac->txcw); - ew32(CTRL, - (ctrl & ~E1000_CTRL_SLU)); + ew32(CTRL, (ctrl & ~E1000_CTRL_SLU)); mac->serdes_link_state = e1000_serdes_link_autoneg_progress; e_dbg("DOWN -> AN_PROG\n"); @@ -1455,9 +1480,9 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw) e_dbg("ANYSTATE -> DOWN\n"); } else { /* - * We have sync, and can tolerate one - * invalid (IV) codeword before declaring - * link down, so reread to look again + * We have sync, and can tolerate one invalid (IV) + * codeword before declaring link down, so reread + * to look again. */ udelay(10); rxcw = er32(RXCW); @@ -1526,7 +1551,7 @@ bool e1000e_get_laa_state_82571(struct e1000_hw *hw) * @hw: pointer to the HW structure * @state: enable/disable locally administered address * - * Enable/Disable the current locally administers address state. + * Enable/Disable the current locally administered address state. **/ void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state) { @@ -1600,6 +1625,28 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw) } /** + * e1000_power_down_phy_copper_82571 - Remove link during PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, remove the link. + **/ +static void e1000_power_down_phy_copper_82571(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + struct e1000_mac_info *mac = &hw->mac; + + if (!(phy->ops.check_reset_block)) + return; + + /* If the management interface is not enabled, then power down */ + if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw))) + e1000_power_down_phy_copper(hw); + + return; +} + +/** * e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters * @hw: pointer to the HW structure * @@ -1656,6 +1703,8 @@ static struct e1000_mac_operations e82571_mac_ops = { /* .led_on: mac type dependent */ .led_off = e1000e_led_off_generic, .update_mc_addr_list = e1000_update_mc_addr_list_82571, + .write_vfta = e1000_write_vfta_generic, + .clear_vfta = e1000_clear_vfta_82571, .reset_hw = e1000_reset_hw_82571, .init_hw = e1000_init_hw_82571, .setup_link = e1000_setup_link_82571, @@ -1665,6 +1714,7 @@ static struct e1000_mac_operations e82571_mac_ops = { static struct e1000_phy_operations e82_phy_ops_igp = { .acquire = e1000_get_hw_semaphore_82571, + .check_polarity = e1000_check_polarity_igp, .check_reset_block = e1000e_check_reset_block_generic, .commit = NULL, .force_speed_duplex = e1000e_phy_force_speed_duplex_igp, @@ -1682,6 +1732,7 @@ static struct e1000_phy_operations e82_phy_ops_igp = { static struct e1000_phy_operations e82_phy_ops_m88 = { .acquire = e1000_get_hw_semaphore_82571, + .check_polarity = e1000_check_polarity_m88, .check_reset_block = e1000e_check_reset_block_generic, .commit = e1000e_phy_sw_reset, .force_speed_duplex = e1000e_phy_force_speed_duplex_m88, @@ -1699,6 +1750,7 @@ static struct e1000_phy_operations e82_phy_ops_m88 = { static struct e1000_phy_operations e82_phy_ops_bm = { .acquire = e1000_get_hw_semaphore_82571, + .check_polarity = e1000_check_polarity_m88, .check_reset_block = e1000e_check_reset_block_generic, .commit = e1000e_phy_sw_reset, .force_speed_duplex = e1000e_phy_force_speed_duplex_m88, diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index c9fcef7f846..cebbd9079d5 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -142,6 +142,8 @@ struct e1000_info; #define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */ #define HV_TNCRS_LOWER PHY_REG(778, 30) +#define E1000_FCRTV_PCH 0x05F40 /* PCH Flow Control Refresh Timer Value */ + /* BM PHY Copper Specific Status */ #define BM_CS_STATUS 17 #define BM_CS_STATUS_LINK_UP 0x0400 @@ -192,12 +194,15 @@ struct e1000_buffer { unsigned long time_stamp; u16 length; u16 next_to_watch; + u16 mapped_as_page; }; /* Rx */ - /* arrays of page information for packet split */ - struct e1000_ps_page *ps_pages; + struct { + /* arrays of page information for packet split */ + struct e1000_ps_page *ps_pages; + struct page *page; + }; }; - struct page *page; }; struct e1000_ring { @@ -507,7 +512,7 @@ extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw); extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw); extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw); extern s32 e1000e_setup_link(struct e1000_hw *hw); -extern void e1000e_clear_vfta(struct e1000_hw *hw); +extern void e1000_clear_vfta_generic(struct e1000_hw *hw); extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw, u8 *mc_addr_list, @@ -523,7 +528,7 @@ extern void e1000e_config_collision_dist(struct e1000_hw *hw); extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw); extern s32 e1000e_force_mac_fc(struct e1000_hw *hw); extern s32 e1000e_blink_led(struct e1000_hw *hw); -extern void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value); +extern void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); extern void e1000e_reset_adaptive(struct e1000_hw *hw); extern void e1000e_update_adaptive(struct e1000_hw *hw); @@ -566,6 +571,8 @@ extern s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, u32 usec_interval, bool *success); extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); +extern void e1000_power_up_phy_copper(struct e1000_hw *hw); +extern void e1000_power_down_phy_copper(struct e1000_hw *hw); extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); extern s32 e1000e_check_downshift(struct e1000_hw *hw); @@ -583,6 +590,12 @@ extern s32 e1000_get_phy_info_82577(struct e1000_hw *hw); extern s32 e1000_phy_force_speed_duplex_82577(struct e1000_hw *hw); extern s32 e1000_get_cable_length_82577(struct e1000_hw *hw); +extern s32 e1000_check_polarity_m88(struct e1000_hw *hw); +extern s32 e1000_get_phy_info_ife(struct e1000_hw *hw); +extern s32 e1000_check_polarity_ife(struct e1000_hw *hw); +extern s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw); +extern s32 e1000_check_polarity_igp(struct e1000_hw *hw); + static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw) { return hw->phy.ops.reset(hw); diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index e50579859e0..d2a10479460 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -99,6 +99,8 @@ */ static const u16 e1000_gg82563_cable_length_table[] = { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF }; +#define GG82563_CABLE_LENGTH_TABLE_SIZE \ + ARRAY_SIZE(e1000_gg82563_cable_length_table) static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw); static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); @@ -112,6 +114,7 @@ static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 *data); static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, u16 data); +static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw); /** * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs. @@ -125,6 +128,9 @@ static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw) if (hw->phy.media_type != e1000_media_type_copper) { phy->type = e1000_phy_none; return 0; + } else { + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_80003es2lan; } phy->addr = 1; @@ -694,20 +700,27 @@ static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw) static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; + s32 ret_val = 0; u16 phy_data, index; ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data); if (ret_val) - return ret_val; + goto out; index = phy_data & GG82563_DSPD_CABLE_LENGTH; + + if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) { + ret_val = -E1000_ERR_PHY; + goto out; + } + phy->min_cable_length = e1000_gg82563_cable_length_table[index]; - phy->max_cable_length = e1000_gg82563_cable_length_table[index+5]; + phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5]; phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; - return 0; +out: + return ret_val; } /** @@ -807,7 +820,7 @@ static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw) /* Disabling VLAN filtering */ e_dbg("Initializing the IEEE VLAN\n"); - e1000e_clear_vfta(hw); + mac->ops.clear_vfta(hw); /* Setup the receive address. */ e1000e_init_rx_addrs(hw, mac->rar_entry_count); @@ -1294,6 +1307,23 @@ static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, } /** + * e1000_power_down_phy_copper_80003es2lan - Remove link during PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, remove the link. + **/ +static void e1000_power_down_phy_copper_80003es2lan(struct e1000_hw *hw) +{ + /* If the management interface is not enabled, then power down */ + if (!(hw->mac.ops.check_mng_mode(hw) || + hw->phy.ops.check_reset_block(hw))) + e1000_power_down_phy_copper(hw); + + return; +} + +/** * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters * @hw: pointer to the HW structure * @@ -1350,6 +1380,8 @@ static struct e1000_mac_operations es2_mac_ops = { .led_on = e1000e_led_on_generic, .led_off = e1000e_led_off_generic, .update_mc_addr_list = e1000e_update_mc_addr_list_generic, + .write_vfta = e1000_write_vfta_generic, + .clear_vfta = e1000_clear_vfta_generic, .reset_hw = e1000_reset_hw_80003es2lan, .init_hw = e1000_init_hw_80003es2lan, .setup_link = e1000e_setup_link, @@ -1359,6 +1391,7 @@ static struct e1000_mac_operations es2_mac_ops = { static struct e1000_phy_operations es2_phy_ops = { .acquire = e1000_acquire_phy_80003es2lan, + .check_polarity = e1000_check_polarity_m88, .check_reset_block = e1000e_check_reset_block_generic, .commit = e1000e_phy_sw_reset, .force_speed_duplex = e1000_phy_force_speed_duplex_80003es2lan, diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index b6243cad310..0aa50c229c7 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -535,7 +535,8 @@ static int e1000_get_eeprom(struct net_device *netdev, if (ret_val) { /* a read error occurred, throw away the result */ - memset(eeprom_buff, 0xff, sizeof(eeprom_buff)); + memset(eeprom_buff, 0xff, sizeof(u16) * + (last_word - first_word + 1)); } else { /* Device's eeprom is always little-endian, word addressable */ for (i = 0; i < last_word - first_word + 1; i++) diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index 426155c15ce..a7d08dae79c 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -219,7 +219,7 @@ enum e1e_registers { E1000_HICR = 0x08F00, /* Host Interface Control */ }; -/* RSS registers */ +#define E1000_MAX_PHY_ADDR 4 /* IGP01E1000 Specific Registers */ #define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ @@ -356,6 +356,7 @@ enum e1e_registers { #define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA #define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB +#define E1000_DEV_ID_ICH8_82567V_3 0x1501 #define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 #define E1000_DEV_ID_ICH8_IGP_AMT 0x104A #define E1000_DEV_ID_ICH8_IGP_C 0x104B @@ -741,6 +742,7 @@ struct e1000_mac_operations { s32 (*check_for_link)(struct e1000_hw *); s32 (*cleanup_led)(struct e1000_hw *); void (*clear_hw_cntrs)(struct e1000_hw *); + void (*clear_vfta)(struct e1000_hw *); s32 (*get_bus_info)(struct e1000_hw *); s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); s32 (*led_on)(struct e1000_hw *); @@ -751,6 +753,7 @@ struct e1000_mac_operations { s32 (*setup_link)(struct e1000_hw *); s32 (*setup_physical_interface)(struct e1000_hw *); s32 (*setup_led)(struct e1000_hw *); + void (*write_vfta)(struct e1000_hw *, u32, u32); }; /* Function pointers for the PHY. */ @@ -772,6 +775,8 @@ struct e1000_phy_operations { s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); s32 (*write_reg)(struct e1000_hw *, u32, u16); s32 (*write_reg_locked)(struct e1000_hw *, u32, u16); + void (*power_up)(struct e1000_hw *); + void (*power_down)(struct e1000_hw *); }; /* Function pointers for the NVM. */ diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 568bb259c6f..7b33be98a2c 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -195,7 +195,6 @@ union ich8_flash_protected_range { static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); -static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw); static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, u8 byte); @@ -217,6 +216,7 @@ static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); static s32 e1000_led_on_pchlan(struct e1000_hw *hw); static s32 e1000_led_off_pchlan(struct e1000_hw *hw); static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); +static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw); static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); @@ -259,26 +259,37 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) phy->addr = 1; phy->reset_delay_us = 100; - phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; phy->ops.read_reg = e1000_read_phy_reg_hv; phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked; phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan; phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan; phy->ops.write_reg = e1000_write_phy_reg_hv; phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked; + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; phy->id = e1000_phy_unknown; e1000e_get_phy_id(hw); phy->type = e1000e_get_phy_type_from_id(phy->id); - if (phy->type == e1000_phy_82577) { + switch (phy->type) { + case e1000_phy_82577: phy->ops.check_polarity = e1000_check_polarity_82577; phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_82577; - phy->ops.get_cable_length = e1000_get_cable_length_82577; + phy->ops.get_cable_length = e1000_get_cable_length_82577; phy->ops.get_info = e1000_get_phy_info_82577; phy->ops.commit = e1000e_phy_sw_reset; + case e1000_phy_82578: + phy->ops.check_polarity = e1000_check_polarity_m88; + phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88; + phy->ops.get_cable_length = e1000e_get_cable_length_m88; + phy->ops.get_info = e1000e_get_phy_info_m88; + break; + default: + ret_val = -E1000_ERR_PHY; + break; } return ret_val; @@ -299,6 +310,9 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) phy->addr = 1; phy->reset_delay_us = 100; + phy->ops.power_up = e1000_power_up_phy_copper; + phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; + /* * We may need to do this twice - once for IGP and if that fails, * we'll set BM func pointers and try again @@ -308,8 +322,10 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) phy->ops.write_reg = e1000e_write_phy_reg_bm; phy->ops.read_reg = e1000e_read_phy_reg_bm; ret_val = e1000e_determine_phy_address(hw); - if (ret_val) + if (ret_val) { + e_dbg("Cannot determine PHY addr. Erroring out\n"); return ret_val; + } } phy->id = 0; @@ -328,12 +344,18 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; phy->ops.read_reg_locked = e1000e_read_phy_reg_igp_locked; phy->ops.write_reg_locked = e1000e_write_phy_reg_igp_locked; + phy->ops.get_info = e1000e_get_phy_info_igp; + phy->ops.check_polarity = e1000_check_polarity_igp; + phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_igp; break; case IFE_E_PHY_ID: case IFE_PLUS_E_PHY_ID: case IFE_C_E_PHY_ID: phy->type = e1000_phy_ife; phy->autoneg_mask = E1000_ALL_NOT_GIG; + phy->ops.get_info = e1000_get_phy_info_ife; + phy->ops.check_polarity = e1000_check_polarity_ife; + phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; break; case BME1000_E_PHY_ID: phy->type = e1000_phy_bm; @@ -341,14 +363,15 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) phy->ops.read_reg = e1000e_read_phy_reg_bm; phy->ops.write_reg = e1000e_write_phy_reg_bm; phy->ops.commit = e1000e_phy_sw_reset; + phy->ops.get_info = e1000e_get_phy_info_m88; + phy->ops.check_polarity = e1000_check_polarity_m88; + phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88; break; default: return -E1000_ERR_PHY; break; } - phy->ops.check_polarity = e1000_check_polarity_ife_ich8lan; - return 0; } @@ -732,77 +755,6 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) } /** - * e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex - * @hw: pointer to the HW structure - * - * Forces the speed and duplex settings of the PHY. - * This is a function pointer entry point only called by - * PHY setup routines. - **/ -static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - if (phy->type != e1000_phy_ife) { - ret_val = e1000e_phy_force_speed_duplex_igp(hw); - return ret_val; - } - - ret_val = e1e_rphy(hw, PHY_CONTROL, &data); - if (ret_val) - return ret_val; - - e1000e_phy_force_speed_duplex_setup(hw, &data); - - ret_val = e1e_wphy(hw, PHY_CONTROL, data); - if (ret_val) - return ret_val; - - /* Disable MDI-X support for 10/100 */ - ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); - if (ret_val) - return ret_val; - - data &= ~IFE_PMC_AUTO_MDIX; - data &= ~IFE_PMC_FORCE_MDIX; - - ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data); - if (ret_val) - return ret_val; - - e_dbg("IFE PMC: %X\n", data); - - udelay(1); - - if (phy->autoneg_wait_to_complete) { - e_dbg("Waiting for forced speed/duplex link on IFE phy.\n"); - - ret_val = e1000e_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - return ret_val; - - if (!link) - e_dbg("Link taking longer than expected.\n"); - - /* Try once more */ - ret_val = e1000e_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - return ret_val; - } - - return 0; -} - -/** * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration * @hw: pointer to the HW structure * @@ -1110,7 +1062,8 @@ static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) oem_reg |= HV_OEM_BITS_LPLU; } /* Restart auto-neg to activate the bits */ - oem_reg |= HV_OEM_BITS_RESTART_AN; + if (!e1000_check_reset_block(hw)) + oem_reg |= HV_OEM_BITS_RESTART_AN; ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg); out: @@ -1253,122 +1206,6 @@ out: } /** - * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states - * @hw: pointer to the HW structure - * - * Populates "phy" structure with various feature states. - * This function is only called by other family-specific - * routines. - **/ -static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - return ret_val; - - if (!link) { - e_dbg("Phy info is only valid if link is up\n"); - return -E1000_ERR_CONFIG; - } - - ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data); - if (ret_val) - return ret_val; - phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE)); - - if (phy->polarity_correction) { - ret_val = phy->ops.check_polarity(hw); - if (ret_val) - return ret_val; - } else { - /* Polarity is forced */ - phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - } - - ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); - if (ret_val) - return ret_val; - - phy->is_mdix = (data & IFE_PMC_MDIX_STATUS); - - /* The following parameters are undefined for 10/100 operation. */ - phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; - phy->local_rx = e1000_1000t_rx_status_undefined; - phy->remote_rx = e1000_1000t_rx_status_undefined; - - return 0; -} - -/** - * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info - * @hw: pointer to the HW structure - * - * Wrapper for calling the get_phy_info routines for the appropriate phy type. - * This is a function pointer entry point called by drivers - * or other shared routines. - **/ -static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw) -{ - switch (hw->phy.type) { - case e1000_phy_ife: - return e1000_get_phy_info_ife_ich8lan(hw); - break; - case e1000_phy_igp_3: - case e1000_phy_bm: - case e1000_phy_82578: - case e1000_phy_82577: - return e1000e_get_phy_info_igp(hw); - break; - default: - break; - } - - return -E1000_ERR_PHY_TYPE; -} - -/** - * e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY - * @hw: pointer to the HW structure - * - * Polarity is determined on the polarity reversal feature being enabled. - * This function is only called by other family-specific - * routines. - **/ -static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, offset, mask; - - /* - * Polarity is determined based on the reversal feature being enabled. - */ - if (phy->polarity_correction) { - offset = IFE_PHY_EXTENDED_STATUS_CONTROL; - mask = IFE_PESC_POLARITY_REVERSED; - } else { - offset = IFE_PHY_SPECIAL_CONTROL; - mask = IFE_PSC_FORCE_POLARITY; - } - - ret_val = e1e_rphy(hw, offset, &phy_data); - - if (!ret_val) - phy->cable_polarity = (phy_data & mask) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - - return ret_val; -} - -/** * e1000_set_lplu_state_pchlan - Set Low Power Link Up state * @hw: pointer to the HW structure * @active: true to enable LPLU, false to disable @@ -1740,7 +1577,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) if (hsfsts.hsf_status.flcinprog == 0) { /* * There is no cycle running at present, - * so we can start a cycle + * so we can start a cycle. * Begin by setting Flash Cycle Done. */ hsfsts.hsf_status.flcdone = 1; @@ -1748,7 +1585,7 @@ static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) ret_val = 0; } else { /* - * otherwise poll for sometime so the current + * Otherwise poll for sometime so the current * cycle has a chance to end before giving up. */ for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { @@ -2638,7 +2475,6 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) ctrl |= E1000_CTRL_PHY_RST; } ret_val = e1000_acquire_swflag_ich8lan(hw); - /* Whether or not the swflag was acquired, we need to reset the part */ e_dbg("Issuing a global reset to ich8lan\n"); ew32(CTRL, (ctrl | E1000_CTRL_RST)); msleep(20); @@ -3197,6 +3033,7 @@ void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw) u32 phy_ctrl; switch (hw->mac.type) { + case e1000_ich8lan: case e1000_ich9lan: case e1000_ich10lan: case e1000_pchlan: @@ -3391,6 +3228,23 @@ static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) } /** + * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, remove the link. + **/ +static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw) +{ + /* If the management interface is not enabled, then power down */ + if (!(hw->mac.ops.check_mng_mode(hw) || + hw->phy.ops.check_reset_block(hw))) + e1000_power_down_phy_copper(hw); + + return; +} + +/** * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters * @hw: pointer to the HW structure * @@ -3459,10 +3313,8 @@ static struct e1000_phy_operations ich8_phy_ops = { .acquire = e1000_acquire_swflag_ich8lan, .check_reset_block = e1000_check_reset_block_ich8lan, .commit = NULL, - .force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan, .get_cfg_done = e1000_get_cfg_done_ich8lan, .get_cable_length = e1000e_get_cable_length_igp_2, - .get_info = e1000_get_phy_info_ich8lan, .read_reg = e1000e_read_phy_reg_igp, .release = e1000_release_swflag_ich8lan, .reset = e1000_phy_hw_reset_ich8lan, @@ -3545,6 +3397,7 @@ struct e1000_info e1000_pch_info = { | FLAG_HAS_AMT | FLAG_HAS_FLASH | FLAG_HAS_JUMBO_FRAMES + | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ | FLAG_APME_IN_WUC, .pba = 26, .max_hw_frame_size = 4096, diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index f690a1055b4..a86c17548c1 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -82,7 +82,24 @@ s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw) } /** - * e1000e_write_vfta - Write value to VLAN filter table + * e1000_clear_vfta_generic - Clear VLAN filter table + * @hw: pointer to the HW structure + * + * Clears the register array which contains the VLAN filter table by + * setting all the values to 0. + **/ +void e1000_clear_vfta_generic(struct e1000_hw *hw) +{ + u32 offset; + + for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { + E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0); + e1e_flush(); + } +} + +/** + * e1000_write_vfta_generic - Write value to VLAN filter table * @hw: pointer to the HW structure * @offset: register offset in VLAN filter table * @value: register value written to VLAN filter table @@ -90,7 +107,7 @@ s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw) * Writes value at the given offset in the register array which stores * the VLAN filter table. **/ -void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) +void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value) { E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value); e1e_flush(); @@ -1069,7 +1086,6 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) * 1 | 1 | 0 | 0 | e1000_fc_none * 1 | 1 | 0 | 1 | e1000_fc_rx_pause * - * * Are both PAUSE bits set to 1? If so, this implies * Symmetric Flow Control is enabled at both ends. The * ASM_DIR bits are irrelevant per the spec. @@ -1107,7 +1123,6 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result *-------|---------|-------|---------|-------------------- * 0 | 1 | 1 | 1 | e1000_fc_tx_pause - * */ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && @@ -1123,7 +1138,6 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result *-------|---------|-------|---------|-------------------- * 1 | 1 | 0 | 1 | e1000_fc_rx_pause - * */ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && @@ -2346,7 +2360,7 @@ static s32 e1000_mng_write_cmd_header(struct e1000_hw *hw, } /** - * e1000_mng_host_if_write - Writes to the manageability host interface + * e1000_mng_host_if_write - Write to the manageability host interface * @hw: pointer to the HW structure * @buffer: pointer to the host interface buffer * @length: size of the buffer diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 11a527484e1..c3105c5087e 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -534,10 +534,17 @@ next_desc: static void e1000_put_txbuf(struct e1000_adapter *adapter, struct e1000_buffer *buffer_info) { - buffer_info->dma = 0; + if (buffer_info->dma) { + if (buffer_info->mapped_as_page) + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + else + pci_unmap_single(adapter->pdev, buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } if (buffer_info->skb) { - skb_dma_unmap(&adapter->pdev->dev, buffer_info->skb, - DMA_TO_DEVICE); dev_kfree_skb_any(buffer_info->skb); buffer_info->skb = NULL; } @@ -672,8 +679,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter) adapter->detect_tx_hung = 0; if (tx_ring->buffer_info[i].time_stamp && time_after(jiffies, tx_ring->buffer_info[i].time_stamp - + (adapter->tx_timeout_factor * HZ)) - && !(er32(STATUS) & E1000_STATUS_TXOFF)) { + + (adapter->tx_timeout_factor * HZ)) && + !(er32(STATUS) & E1000_STATUS_TXOFF)) { schedule_work(&adapter->print_hang_task); netif_stop_queue(netdev); } @@ -2031,11 +2038,14 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid) E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && (vid == adapter->mng_vlan_id)) return; + /* add VID to filter table */ - index = (vid >> 5) & 0x7F; - vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); - vfta |= (1 << (vid & 0x1F)); - e1000e_write_vfta(hw, index, vfta); + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + index = (vid >> 5) & 0x7F; + vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); + vfta |= (1 << (vid & 0x1F)); + hw->mac.ops.write_vfta(hw, index, vfta); + } } static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) @@ -2060,10 +2070,12 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) } /* remove VID from filter table */ - index = (vid >> 5) & 0x7F; - vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); - vfta &= ~(1 << (vid & 0x1F)); - e1000e_write_vfta(hw, index, vfta); + if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { + index = (vid >> 5) & 0x7F; + vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index); + vfta &= ~(1 << (vid & 0x1F)); + hw->mac.ops.write_vfta(hw, index, vfta); + } } static void e1000_update_mng_vlan(struct e1000_adapter *adapter) @@ -2636,18 +2648,8 @@ static void e1000_configure(struct e1000_adapter *adapter) **/ void e1000e_power_up_phy(struct e1000_adapter *adapter) { - u16 mii_reg = 0; - - /* Just clear the power down bit to wake the phy back up */ - if (adapter->hw.phy.media_type == e1000_media_type_copper) { - /* - * According to the manual, the phy will retain its - * settings across a power-down/up cycle - */ - e1e_rphy(&adapter->hw, PHY_CONTROL, &mii_reg); - mii_reg &= ~MII_CR_POWER_DOWN; - e1e_wphy(&adapter->hw, PHY_CONTROL, mii_reg); - } + if (adapter->hw.phy.ops.power_up) + adapter->hw.phy.ops.power_up(&adapter->hw); adapter->hw.mac.ops.setup_link(&adapter->hw); } @@ -2655,35 +2657,17 @@ void e1000e_power_up_phy(struct e1000_adapter *adapter) /** * e1000_power_down_phy - Power down the PHY * - * Power down the PHY so no link is implied when interface is down - * The PHY cannot be powered down is management or WoL is active + * Power down the PHY so no link is implied when interface is down. + * The PHY cannot be powered down if management or WoL is active. */ static void e1000_power_down_phy(struct e1000_adapter *adapter) { - struct e1000_hw *hw = &adapter->hw; - u16 mii_reg; - /* WoL is enabled */ if (adapter->wol) return; - /* non-copper PHY? */ - if (adapter->hw.phy.media_type != e1000_media_type_copper) - return; - - /* reset is blocked because of a SoL/IDER session */ - if (e1000e_check_mng_mode(hw) || e1000_check_reset_block(hw)) - return; - - /* manageability (AMT) is enabled */ - if (er32(MANC) & E1000_MANC_SMBUS_EN) - return; - - /* power down the PHY */ - e1e_rphy(hw, PHY_CONTROL, &mii_reg); - mii_reg |= MII_CR_POWER_DOWN; - e1e_wphy(hw, PHY_CONTROL, mii_reg); - mdelay(1); + if (adapter->hw.phy.ops.power_down) + adapter->hw.phy.ops.power_down(&adapter->hw); } /** @@ -2760,25 +2744,38 @@ void e1000e_reset(struct e1000_adapter *adapter) /* * flow control settings * - * The high water mark must be low enough to fit two full frame + * The high water mark must be low enough to fit one full frame * (or the size used for early receive) above it in the Rx FIFO. * Set it to the lower of: * - 90% of the Rx FIFO size, and * - the full Rx FIFO size minus the early receive size (for parts * with ERT support assuming ERT set to E1000_ERT_2048), or - * - the full Rx FIFO size minus two full frames + * - the full Rx FIFO size minus one full frame */ - if ((adapter->flags & FLAG_HAS_ERT) && - (adapter->netdev->mtu > ETH_DATA_LEN)) - hwm = min(((pba << 10) * 9 / 10), - ((pba << 10) - (E1000_ERT_2048 << 3))); - else - hwm = min(((pba << 10) * 9 / 10), - ((pba << 10) - (2 * adapter->max_frame_size))); + if (hw->mac.type == e1000_pchlan) { + /* + * Workaround PCH LOM adapter hangs with certain network + * loads. If hangs persist, try disabling Tx flow control. + */ + if (adapter->netdev->mtu > ETH_DATA_LEN) { + fc->high_water = 0x3500; + fc->low_water = 0x1500; + } else { + fc->high_water = 0x5000; + fc->low_water = 0x3000; + } + } else { + if ((adapter->flags & FLAG_HAS_ERT) && + (adapter->netdev->mtu > ETH_DATA_LEN)) + hwm = min(((pba << 10) * 9 / 10), + ((pba << 10) - (E1000_ERT_2048 << 3))); + else + hwm = min(((pba << 10) * 9 / 10), + ((pba << 10) - adapter->max_frame_size)); - fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */ - fc->low_water = (fc->high_water - (2 * adapter->max_frame_size)); - fc->low_water &= E1000_FCRTL_RTL; /* 8-byte granularity */ + fc->high_water = hwm & E1000_FCRTH_RTH; /* 8-byte granularity */ + fc->low_water = fc->high_water - 8; + } if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME) fc->pause_time = 0xFFFF; @@ -2804,6 +2801,10 @@ void e1000e_reset(struct e1000_adapter *adapter) if (mac->ops.init_hw(hw)) e_err("Hardware Error\n"); + /* additional part of the flow-control workaround above */ + if (hw->mac.type == e1000_pchlan) + ew32(FCRTV_PCH, 0x1000); + e1000_update_mng_vlan(adapter); /* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */ @@ -3612,7 +3613,7 @@ static void e1000_watchdog_task(struct work_struct *work) case SPEED_100: txb2b = 0; netdev->tx_queue_len = 100; - /* maybe add some timeout factor ? */ + adapter->tx_timeout_factor = 10; break; } @@ -3890,23 +3891,14 @@ static int e1000_tx_map(struct e1000_adapter *adapter, unsigned int mss) { struct e1000_ring *tx_ring = adapter->tx_ring; + struct pci_dev *pdev = adapter->pdev; struct e1000_buffer *buffer_info; unsigned int len = skb_headlen(skb); - unsigned int offset, size, count = 0, i; + unsigned int offset = 0, size, count = 0, i; unsigned int f; - dma_addr_t *map; i = tx_ring->next_to_use; - if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) { - dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); - adapter->tx_dma_failed++; - return 0; - } - - map = skb_shinfo(skb)->dma_maps; - offset = 0; - while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, max_per_txd); @@ -3914,11 +3906,15 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = skb_shinfo(skb)->dma_head + offset; - count++; + buffer_info->dma = pci_map_single(pdev, skb->data + offset, + size, PCI_DMA_TODEVICE); + buffer_info->mapped_as_page = false; + if (pci_dma_mapping_error(pdev, buffer_info->dma)) + goto dma_error; len -= size; offset += size; + count++; if (len) { i++; @@ -3932,7 +3928,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter, frag = &skb_shinfo(skb)->frags[f]; len = frag->size; - offset = 0; + offset = frag->page_offset; while (len) { i++; @@ -3945,7 +3941,12 @@ static int e1000_tx_map(struct e1000_adapter *adapter, buffer_info->length = size; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[f] + offset; + buffer_info->dma = pci_map_page(pdev, frag->page, + offset, size, + PCI_DMA_TODEVICE); + buffer_info->mapped_as_page = true; + if (pci_dma_mapping_error(pdev, buffer_info->dma)) + goto dma_error; len -= size; offset += size; @@ -3957,6 +3958,22 @@ static int e1000_tx_map(struct e1000_adapter *adapter, tx_ring->buffer_info[first].next_to_watch = i; return count; + +dma_error: + dev_err(&pdev->dev, "TX DMA map failed\n"); + buffer_info->dma = 0; + count--; + + while (count >= 0) { + count--; + i--; + if (i < 0) + i += tx_ring->count; + buffer_info = &tx_ring->buffer_info[i]; + e1000_put_txbuf(adapter, buffer_info);; + } + + return 0; } static void e1000_tx_queue(struct e1000_adapter *adapter, @@ -4029,8 +4046,8 @@ static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter, u16 length, offset; if (vlan_tx_tag_present(skb)) { - if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) - && (adapter->hw.mng_cookie.status & + if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) && + (adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN))) return 0; } @@ -4284,8 +4301,10 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) msleep(1); - /* e1000e_down has a dependency on max_frame_size */ + /* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */ adapter->max_frame_size = max_frame; + e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); + netdev->mtu = new_mtu; if (netif_running(netdev)) e1000e_down(adapter); @@ -4315,9 +4334,6 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN; - e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); - netdev->mtu = new_mtu; - if (netif_running(netdev)) e1000e_up(adapter); else @@ -5273,17 +5289,17 @@ static void __devexit e1000_remove(struct pci_dev *pdev) cancel_work_sync(&adapter->print_hang_task); flush_scheduled_work(); + if (!(netdev->flags & IFF_UP)) + e1000_power_down_phy(adapter); + + unregister_netdev(netdev); + /* * Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ e1000_release_hw_control(adapter); - unregister_netdev(netdev); - - if (!e1000_check_reset_block(&adapter->hw)) - e1000_phy_hw_reset(&adapter->hw); - e1000e_reset_interrupt_capability(adapter); kfree(adapter->tx_ring); kfree(adapter->rx_ring); @@ -5349,6 +5365,7 @@ static struct pci_device_id e1000_pci_tbl[] = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_82567V_3), board_ich8lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan }, diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 99d53fae430..55a2c0acfee 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -44,6 +44,8 @@ static s32 e1000_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, /* Cable length tables */ static const u16 e1000_m88_cable_length_table[] = { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; +#define M88E1000_CABLE_LENGTH_TABLE_SIZE \ + ARRAY_SIZE(e1000_m88_cable_length_table) static const u16 e1000_igp_2_cable_length_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, 0, 0, 0, 3, @@ -71,7 +73,6 @@ static const u16 e1000_igp_2_cable_length_table[] = #define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15) #define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */ #define I82577_CTRL_REG 23 -#define I82577_CTRL_DOWNSHIFT_MASK (7 << 10) /* 82577 specific PHY registers */ #define I82577_PHY_CTRL_2 18 @@ -152,10 +153,10 @@ s32 e1000e_get_phy_id(struct e1000_hw *hw) goto out; /* - * If the PHY ID is still unknown, we may have an 82577i - * without link. We will try again after setting Slow - * MDIC mode. No harm in trying again in this case since - * the PHY ID is unknown at this point anyway + * If the PHY ID is still unknown, we may have an 82577 + * without link. We will try again after setting Slow MDIC + * mode. No harm in trying again in this case since the PHY + * ID is unknown at this point anyway. */ ret_val = phy->ops.acquire(hw); if (ret_val) @@ -660,15 +661,6 @@ s32 e1000_copper_link_setup_82577(struct e1000_hw *hw) phy_data |= I82577_CFG_ENABLE_DOWNSHIFT; ret_val = phy->ops.write_reg(hw, I82577_CFG_REG, phy_data); - if (ret_val) - goto out; - - /* Set number of link attempts before downshift */ - ret_val = phy->ops.read_reg(hw, I82577_CTRL_REG, &phy_data); - if (ret_val) - goto out; - phy_data &= ~I82577_CTRL_DOWNSHIFT_MASK; - ret_val = phy->ops.write_reg(hw, I82577_CTRL_REG, phy_data); out: return ret_val; @@ -1330,17 +1322,22 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw) return ret_val; if (!link) { - /* - * We didn't get link. - * Reset the DSP and cross our fingers. - */ - ret_val = e1e_wphy(hw, M88E1000_PHY_PAGE_SELECT, - 0x001d); - if (ret_val) - return ret_val; - ret_val = e1000e_phy_reset_dsp(hw); - if (ret_val) - return ret_val; + if (hw->phy.type != e1000_phy_m88) { + e_dbg("Link taking longer than expected.\n"); + } else { + /* + * We didn't get link. + * Reset the DSP and cross our fingers. + */ + ret_val = e1e_wphy(hw, + M88E1000_PHY_PAGE_SELECT, + 0x001d); + if (ret_val) + return ret_val; + ret_val = e1000e_phy_reset_dsp(hw); + if (ret_val) + return ret_val; + } } /* Try once more */ @@ -1350,6 +1347,9 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw) return ret_val; } + if (hw->phy.type != e1000_phy_m88) + return 0; + ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); if (ret_val) return ret_val; @@ -1379,6 +1379,73 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw) } /** + * e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex + * @hw: pointer to the HW structure + * + * Forces the speed and duplex settings of the PHY. + * This is a function pointer entry point only called by + * PHY setup routines. + **/ +s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + ret_val = e1e_rphy(hw, PHY_CONTROL, &data); + if (ret_val) + goto out; + + e1000e_phy_force_speed_duplex_setup(hw, &data); + + ret_val = e1e_wphy(hw, PHY_CONTROL, data); + if (ret_val) + goto out; + + /* Disable MDI-X support for 10/100 */ + ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); + if (ret_val) + goto out; + + data &= ~IFE_PMC_AUTO_MDIX; + data &= ~IFE_PMC_FORCE_MDIX; + + ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data); + if (ret_val) + goto out; + + e_dbg("IFE PMC: %X\n", data); + + udelay(1); + + if (phy->autoneg_wait_to_complete) { + e_dbg("Waiting for forced speed/duplex link on IFE phy.\n"); + + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + + if (!link) + e_dbg("Link taking longer than expected.\n"); + + /* Try once more */ + ret_val = e1000e_phy_has_link_generic(hw, + PHY_FORCE_LIMIT, + 100000, + &link); + if (ret_val) + goto out; + } + +out: + return ret_val; +} + +/** * e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex * @hw: pointer to the HW structure * @phy_ctrl: pointer to current value of PHY_CONTROL @@ -1533,8 +1600,8 @@ s32 e1000e_check_downshift(struct e1000_hw *hw) switch (phy->type) { case e1000_phy_m88: case e1000_phy_gg82563: + case e1000_phy_bm: case e1000_phy_82578: - case e1000_phy_82577: offset = M88E1000_PHY_SPEC_STATUS; mask = M88E1000_PSSR_DOWNSHIFT; break; @@ -1565,7 +1632,7 @@ s32 e1000e_check_downshift(struct e1000_hw *hw) * * Polarity is determined based on the PHY specific status register. **/ -static s32 e1000_check_polarity_m88(struct e1000_hw *hw) +s32 e1000_check_polarity_m88(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; s32 ret_val; @@ -1590,7 +1657,7 @@ static s32 e1000_check_polarity_m88(struct e1000_hw *hw) * Polarity is determined based on the PHY port status register, and the * current speed (since there is no polarity at 100Mbps). **/ -static s32 e1000_check_polarity_igp(struct e1000_hw *hw) +s32 e1000_check_polarity_igp(struct e1000_hw *hw) { struct e1000_phy_info *phy = &hw->phy; s32 ret_val; @@ -1628,6 +1695,39 @@ static s32 e1000_check_polarity_igp(struct e1000_hw *hw) } /** + * e1000_check_polarity_ife - Check cable polarity for IFE PHY + * @hw: pointer to the HW structure + * + * Polarity is determined on the polarity reversal feature being enabled. + **/ +s32 e1000_check_polarity_ife(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 phy_data, offset, mask; + + /* + * Polarity is determined based on the reversal feature being enabled. + */ + if (phy->polarity_correction) { + offset = IFE_PHY_EXTENDED_STATUS_CONTROL; + mask = IFE_PESC_POLARITY_REVERSED; + } else { + offset = IFE_PHY_SPECIAL_CONTROL; + mask = IFE_PSC_FORCE_POLARITY; + } + + ret_val = e1e_rphy(hw, offset, &phy_data); + + if (!ret_val) + phy->cable_polarity = (phy_data & mask) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + + return ret_val; +} + +/** * e1000_wait_autoneg - Wait for auto-neg completion * @hw: pointer to the HW structure * @@ -1727,15 +1827,21 @@ s32 e1000e_get_cable_length_m88(struct e1000_hw *hw) ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); if (ret_val) - return ret_val; + goto out; index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> - M88E1000_PSSR_CABLE_LENGTH_SHIFT; + M88E1000_PSSR_CABLE_LENGTH_SHIFT; + if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { + ret_val = -E1000_ERR_PHY; + goto out; + } + phy->min_cable_length = e1000_m88_cable_length_table[index]; - phy->max_cable_length = e1000_m88_cable_length_table[index+1]; + phy->max_cable_length = e1000_m88_cable_length_table[index + 1]; phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; +out: return ret_val; } @@ -1746,7 +1852,7 @@ s32 e1000e_get_cable_length_m88(struct e1000_hw *hw) * The automatic gain control (agc) normalizes the amplitude of the * received signal, adjusting for the attenuation produced by the * cable. By reading the AGC registers, which represent the - * combination of course and fine gain value, the value can be put + * combination of coarse and fine gain value, the value can be put * into a lookup table to obtain the approximate cable length * for each channel. **/ @@ -1771,7 +1877,7 @@ s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw) /* * Getting bits 15:9, which represent the combination of - * course and fine gain values. The result is a number + * coarse and fine gain values. The result is a number * that can be put into the lookup table to obtain the * approximate cable length. */ @@ -1825,7 +1931,7 @@ s32 e1000e_get_phy_info_m88(struct e1000_hw *hw) u16 phy_data; bool link; - if (hw->phy.media_type != e1000_media_type_copper) { + if (phy->media_type != e1000_media_type_copper) { e_dbg("Phy info is only valid for copper media\n"); return -E1000_ERR_CONFIG; } @@ -1946,6 +2052,61 @@ s32 e1000e_get_phy_info_igp(struct e1000_hw *hw) } /** + * e1000_get_phy_info_ife - Retrieves various IFE PHY states + * @hw: pointer to the HW structure + * + * Populates "phy" structure with various feature states. + **/ +s32 e1000_get_phy_info_ife(struct e1000_hw *hw) +{ + struct e1000_phy_info *phy = &hw->phy; + s32 ret_val; + u16 data; + bool link; + + ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); + if (ret_val) + goto out; + + if (!link) { + e_dbg("Phy info is only valid if link is up\n"); + ret_val = -E1000_ERR_CONFIG; + goto out; + } + + ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data); + if (ret_val) + goto out; + phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE) + ? false : true; + + if (phy->polarity_correction) { + ret_val = e1000_check_polarity_ife(hw); + if (ret_val) + goto out; + } else { + /* Polarity is forced */ + phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) + ? e1000_rev_polarity_reversed + : e1000_rev_polarity_normal; + } + + ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); + if (ret_val) + goto out; + + phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false; + + /* The following parameters are undefined for 10/100 operation. */ + phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; + phy->local_rx = e1000_1000t_rx_status_undefined; + phy->remote_rx = e1000_1000t_rx_status_undefined; + +out: + return ret_val; +} + +/** * e1000e_phy_sw_reset - PHY software reset * @hw: pointer to the HW structure * @@ -2199,28 +2360,34 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id) s32 e1000e_determine_phy_address(struct e1000_hw *hw) { s32 ret_val = -E1000_ERR_PHY_TYPE; - u32 phy_addr= 0; - u32 i = 0; + u32 phy_addr = 0; + u32 i; enum e1000_phy_type phy_type = e1000_phy_unknown; - do { - for (phy_addr = 0; phy_addr < 4; phy_addr++) { - hw->phy.addr = phy_addr; + hw->phy.id = phy_type; + + for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) { + hw->phy.addr = phy_addr; + i = 0; + + do { e1000e_get_phy_id(hw); phy_type = e1000e_get_phy_type_from_id(hw->phy.id); - /* + /* * If phy_type is valid, break - we found our * PHY address */ if (phy_type != e1000_phy_unknown) { ret_val = 0; - break; + goto out; } - } - i++; - } while ((ret_val != 0) && (i < 100)); + msleep(1); + i++; + } while (i < 10); + } +out: return ret_val; } @@ -2474,7 +2641,7 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, /* Gig must be disabled for MDIO accesses to page 800 */ if ((hw->mac.type == e1000_pchlan) && (!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE))) - e_dbg("Attempting to access page 800 while gig enabled\n"); + e_dbg("Attempting to access page 800 while gig enabled.\n"); /* All operations in this function are phy address 1 */ hw->phy.addr = 1; @@ -2484,20 +2651,26 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg); - if (ret_val) + if (ret_val) { + e_dbg("Could not read PHY page 769\n"); goto out; + } /* First clear bit 4 to avoid a power state change */ phy_reg &= ~(BM_WUC_HOST_WU_BIT); ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); - if (ret_val) + if (ret_val) { + e_dbg("Could not clear PHY page 769 bit 4\n"); goto out; + } /* Write bit 2 = 1, and clear bit 4 to 769_17 */ ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg | BM_WUC_ENABLE_BIT); - if (ret_val) + if (ret_val) { + e_dbg("Could not write PHY page 769 bit 2\n"); goto out; + } /* Select page 800 */ ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, @@ -2505,21 +2678,25 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, /* Write the page 800 offset value using opcode 0x11 */ ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg); - if (ret_val) + if (ret_val) { + e_dbg("Could not write address opcode to page 800\n"); goto out; + } if (read) { /* Read the page 800 value using opcode 0x12 */ ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE, data); } else { - /* Read the page 800 value using opcode 0x12 */ + /* Write the page 800 value using opcode 0x12 */ ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE, *data); } - if (ret_val) + if (ret_val) { + e_dbg("Could not access data value from page 800\n"); goto out; + } /* * Restore 769_17.2 to its original value @@ -2530,12 +2707,53 @@ static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, /* Clear 769_17.2 */ ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); + if (ret_val) { + e_dbg("Could not clear PHY page 769 bit 2\n"); + goto out; + } out: return ret_val; } /** + * e1000_power_up_phy_copper - Restore copper link in case of PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, restore the link to previous + * settings. + **/ +void e1000_power_up_phy_copper(struct e1000_hw *hw) +{ + u16 mii_reg = 0; + + /* The PHY will retain its settings across a power down/up cycle */ + e1e_rphy(hw, PHY_CONTROL, &mii_reg); + mii_reg &= ~MII_CR_POWER_DOWN; + e1e_wphy(hw, PHY_CONTROL, mii_reg); +} + +/** + * e1000_power_down_phy_copper - Restore copper link in case of PHY power down + * @hw: pointer to the HW structure + * + * In the case of a PHY power down to save power, or to turn off link during a + * driver unload, or wake on lan is not enabled, restore the link to previous + * settings. + **/ +void e1000_power_down_phy_copper(struct e1000_hw *hw) +{ + u16 mii_reg = 0; + + /* The PHY will retain its settings across a power down/up cycle */ + e1e_rphy(hw, PHY_CONTROL, &mii_reg); + mii_reg |= MII_CR_POWER_DOWN; + e1e_wphy(hw, PHY_CONTROL, mii_reg); + msleep(1); +} + +/** * e1000e_commit_phy - Soft PHY reset * @hw: pointer to the HW structure * @@ -2658,19 +2876,18 @@ static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data, page = 0; if (reg > MAX_PHY_MULTI_PAGE_REG) { - if ((hw->phy.type != e1000_phy_82578) || - ((reg != I82578_ADDR_REG) && - (reg != I82578_ADDR_REG + 1))) { - u32 phy_addr = hw->phy.addr; - - hw->phy.addr = 1; - - /* Page is shifted left, PHY expects (page x 32) */ - ret_val = e1000e_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (page << IGP_PAGE_SHIFT)); - hw->phy.addr = phy_addr; - } + u32 phy_addr = hw->phy.addr; + + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000e_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + hw->phy.addr = phy_addr; + + if (ret_val) + goto out; } ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, @@ -2678,7 +2895,7 @@ static s32 __e1000_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data, out: /* Revert to MDIO fast mode, if applicable */ if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) - ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + ret_val |= e1000_set_mdio_slow_mode_hv(hw, false); if (!locked) hw->phy.ops.release(hw); @@ -2784,19 +3001,18 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data, } if (reg > MAX_PHY_MULTI_PAGE_REG) { - if ((hw->phy.type != e1000_phy_82578) || - ((reg != I82578_ADDR_REG) && - (reg != I82578_ADDR_REG + 1))) { - u32 phy_addr = hw->phy.addr; - - hw->phy.addr = 1; - - /* Page is shifted left, PHY expects (page x 32) */ - ret_val = e1000e_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (page << IGP_PAGE_SHIFT)); - hw->phy.addr = phy_addr; - } + u32 phy_addr = hw->phy.addr; + + hw->phy.addr = 1; + + /* Page is shifted left, PHY expects (page x 32) */ + ret_val = e1000e_write_phy_reg_mdic(hw, + IGP01E1000_PHY_PAGE_SELECT, + (page << IGP_PAGE_SHIFT)); + hw->phy.addr = phy_addr; + + if (ret_val) + goto out; } ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, @@ -2805,7 +3021,7 @@ static s32 __e1000_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data, out: /* Revert to MDIO fast mode, if applicable */ if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) - ret_val = e1000_set_mdio_slow_mode_hv(hw, false); + ret_val |= e1000_set_mdio_slow_mode_hv(hw, false); if (!locked) hw->phy.ops.release(hw); diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index d2f6ee1a629..ca93c9a9d37 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -186,9 +186,9 @@ static int __init e21_probe1(struct net_device *dev, int ioaddr) return -EBUSY; /* First check the station address for the Ctron prefix. */ - if (inb(ioaddr + E21_SAPROM + 0) != 0x00 - || inb(ioaddr + E21_SAPROM + 1) != 0x00 - || inb(ioaddr + E21_SAPROM + 2) != 0x1d) { + if (inb(ioaddr + E21_SAPROM + 0) != 0x00 || + inb(ioaddr + E21_SAPROM + 1) != 0x00 || + inb(ioaddr + E21_SAPROM + 2) != 0x1d) { retval = -ENODEV; goto out; } diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 7f8fcc2fa74..7b62336e673 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -189,8 +189,8 @@ static void ehea_update_firmware_handles(void) for (k = 0; k < EHEA_MAX_PORTS; k++) { struct ehea_port *port = adapter->port[k]; - if (!port || (port->state != EHEA_PORT_UP) - || (num_ports == 0)) + if (!port || (port->state != EHEA_PORT_UP) || + (num_ports == 0)) continue; for (l = 0; @@ -657,8 +657,8 @@ static int get_skb_hdr(struct sk_buff *skb, void **iphdr, static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe, struct sk_buff *skb) { - int vlan_extracted = (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) - && pr->port->vgrp; + int vlan_extracted = ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) && + pr->port->vgrp); if (use_lro) { if (vlan_extracted) @@ -1389,8 +1389,8 @@ out: int ehea_rem_smrs(struct ehea_port_res *pr) { - if ((ehea_rem_mr(&pr->send_mr)) - || (ehea_rem_mr(&pr->recv_mr))) + if ((ehea_rem_mr(&pr->send_mr)) || + (ehea_rem_mr(&pr->recv_mr))) return -EIO; else return 0; @@ -2031,8 +2031,8 @@ static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev, write_ip_start_end(swqe, skb); if (iph->protocol == IPPROTO_UDP) { - if ((iph->frag_off & IP_MF) - || (iph->frag_off & IP_OFFSET)) + if ((iph->frag_off & IP_MF) || + (iph->frag_off & IP_OFFSET)) /* IP fragment, so don't change cs */ swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM; else @@ -2077,8 +2077,8 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, write_tcp_offset_end(swqe, skb); } else if (iph->protocol == IPPROTO_UDP) { - if ((iph->frag_off & IP_MF) - || (iph->frag_off & IP_OFFSET)) + if ((iph->frag_off & IP_MF) || + (iph->frag_off & IP_OFFSET)) /* IP fragment, so don't change cs */ swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IMM_DATA_PRESENT; diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index bc7c5b7abb8..18d405f78c0 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -837,8 +837,8 @@ static u64 ehea_reg_mr_section(int top, int dir, int idx, u64 *pt, hret = ehea_h_register_rpage_mr(adapter->handle, mr->handle, 0, 0, pt_abs, EHEA_MAX_RPAGE); - if ((hret != H_SUCCESS) - && (hret != H_PAGE_REGISTERED)) { + if ((hret != H_SUCCESS) && + (hret != H_PAGE_REGISTERED)) { ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE); ehea_error("register_rpage_mr failed"); diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 703b4c8e9b4..41494f7b2ec 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -630,8 +630,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) barrier(); if ((inl(ioaddr + MIICtrl) & MII_READOP) == 0) { /* Work around read failure bug. */ - if (phy_id == 1 && location < 6 - && inw(ioaddr + MIIData) == 0xffff) { + if (phy_id == 1 && location < 6 && + inw(ioaddr + MIIData) == 0xffff) { outl(read_cmd, ioaddr + MIICtrl); continue; } @@ -1205,8 +1205,8 @@ static int epic_rx(struct net_device *dev, int budget) } /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + if (pkt_len < rx_copybreak && + (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(ep->pci_dev, ep->rx_ring[entry].bufaddr, diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index e173515790c..dac4e595589 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -1629,8 +1629,8 @@ static int netdev_rx(struct net_device *dev) if (debug) printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", rx_status); - if ((!((rx_status & RXFSD) && (rx_status & RXLSD))) - || (rx_status & ErrorSummary)) { + if ((!((rx_status & RXFSD) && (rx_status & RXLSD))) || + (rx_status & ErrorSummary)) { if (rx_status & ErrorSummary) { /* there was a fatal error */ if (debug) printk(KERN_DEBUG @@ -1655,8 +1655,8 @@ static int netdev_rx(struct net_device *dev) cur = np->cur_rx; while (desno <= np->really_rx_count) { ++desno; - if ((!(cur->status & RXOWN)) - && (cur->status & RXLSD)) + if ((!(cur->status & RXOWN)) && + (cur->status & RXLSD)) break; /* goto next rx descriptor */ cur = cur->next_desc_logical; @@ -1786,8 +1786,8 @@ static void __set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = CR_W_AB | CR_W_AM; diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c index b31c9c8876e..b98c6c51229 100644 --- a/drivers/net/gianfar_sysfs.c +++ b/drivers/net/gianfar_sysfs.c @@ -62,8 +62,8 @@ static ssize_t gfar_set_bd_stash(struct device *dev, /* Find out the new setting */ if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1)) new_setting = 1; - else if (!strncmp("off", buf, count - 1) - || !strncmp("0", buf, count - 1)) + else if (!strncmp("off", buf, count - 1) || + !strncmp("0", buf, count - 1)) new_setting = 0; else return count; diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 5d8c6333070..ea85075a89a 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1566,8 +1566,8 @@ static int hamachi_rx(struct net_device *dev) #endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + if (pkt_len < rx_copybreak && + (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { #ifdef RX_CHECKSUM printk(KERN_ERR "%s: rx_copybreak non-zero " "not good with RX_CHECKSUM\n", dev->name); @@ -1722,10 +1722,10 @@ static void hamachi_error(struct net_device *dev, int intr_status) readl(ioaddr + 0x370); readl(ioaddr + 0x3F0); } - if ((intr_status & ~(LinkChange|StatsMax|NegotiationChange|IntrRxDone|IntrTxDone)) - && hamachi_debug) + if ((intr_status & ~(LinkChange|StatsMax|NegotiationChange|IntrRxDone|IntrTxDone)) && + hamachi_debug) printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", - dev->name, intr_status); + dev->name, intr_status); /* Hmmmmm, it's not clear how to recover from PCI faults. */ if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) hmp->stats.tx_fifo_errors++; diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index fe893c91a01..ae5f11c8fc1 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -167,10 +167,7 @@ static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev) static inline int dev_is_ethdev(struct net_device *dev) { - return ( - dev->type == ARPHRD_ETHER - && strncmp(dev->name, "dummy", 5) - ); + return (dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5)); } /* ------------------------------------------------------------------------ */ @@ -186,7 +183,7 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty struct ethhdr *eth; struct bpqdev *bpq; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) goto drop; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -552,7 +549,7 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (!dev_is_ethdev(dev)) diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index 950f3bb21f9..9ee76b42668 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -331,8 +331,8 @@ static int __init dmascc_init(void) for (i = 0; i < MAX_NUM_DEVS && io[i]; i++) { j = (io[i] - hw[h].io_region) / hw[h].io_delta; - if (j >= 0 && j < hw[h].num_devs - && hw[h].io_region + + if (j >= 0 && j < hw[h].num_devs && + hw[h].io_region + j * hw[h].io_delta == io[i]) { base[j] = io[i]; } @@ -396,8 +396,8 @@ static int __init dmascc_init(void) t_val = inb(t1[i]) + (inb(t1[i]) << 8); /* Also check whether counter did wrap */ - if (t_val == 0 - || t_val > TMR_0_HZ / HZ * 10) + if (t_val == 0 || + t_val > TMR_0_HZ / HZ * 10) counting[i] = 0; delay[i] = jiffies - start[i]; } diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 0486cbe01ad..efdbcad63c6 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -187,8 +187,8 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) return -EBUSY; /* Check for the HP+ signature, 50 48 0x 53. */ - if (inw(ioaddr + HP_ID) != 0x4850 - || (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) { + if (inw(ioaddr + HP_ID) != 0x4850 || + (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) { retval = -ENODEV; goto out; } diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index dd866513806..90f890e7c5e 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -993,8 +993,8 @@ static void hp100_mmuinit(struct net_device *dev) if (lp->mode == 1) { /* only needed for Busmaster */ int xmit_stop, recv_stop; - if ((lp->chip == HP100_CHIPID_RAINIER) - || (lp->chip == HP100_CHIPID_SHASTA)) { + if ((lp->chip == HP100_CHIPID_RAINIER) || + (lp->chip == HP100_CHIPID_SHASTA)) { int pdl_stop; /* diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index af117c626e7..fb5e019169e 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1976,27 +1976,27 @@ static int emac_ethtool_set_settings(struct net_device *ndev, if (cmd->autoneg == AUTONEG_DISABLE) { switch (cmd->speed) { case SPEED_10: - if (cmd->duplex == DUPLEX_HALF - && !(f & SUPPORTED_10baseT_Half)) + if (cmd->duplex == DUPLEX_HALF && + !(f & SUPPORTED_10baseT_Half)) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL - && !(f & SUPPORTED_10baseT_Full)) + if (cmd->duplex == DUPLEX_FULL && + !(f & SUPPORTED_10baseT_Full)) return -EINVAL; break; case SPEED_100: - if (cmd->duplex == DUPLEX_HALF - && !(f & SUPPORTED_100baseT_Half)) + if (cmd->duplex == DUPLEX_HALF && + !(f & SUPPORTED_100baseT_Half)) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL - && !(f & SUPPORTED_100baseT_Full)) + if (cmd->duplex == DUPLEX_FULL && + !(f & SUPPORTED_100baseT_Full)) return -EINVAL; break; case SPEED_1000: - if (cmd->duplex == DUPLEX_HALF - && !(f & SUPPORTED_1000baseT_Half)) + if (cmd->duplex == DUPLEX_HALF && + !(f & SUPPORTED_1000baseT_Half)) return -EINVAL; - if (cmd->duplex == DUPLEX_FULL - && !(f & SUPPORTED_1000baseT_Full)) + if (cmd->duplex == DUPLEX_FULL && + !(f & SUPPORTED_1000baseT_Full)) return -EINVAL; break; default: diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index c458d9b188b..b1c1eb88893 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -137,12 +137,13 @@ struct igb_buffer { unsigned long time_stamp; u16 length; u16 next_to_watch; + u16 mapped_as_page; }; /* RX */ struct { struct page *page; - u64 page_dma; - unsigned int page_offset; + dma_addr_t page_dma; + u16 page_offset; }; }; }; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index bb1a6eeade0..16349ba6873 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -2654,16 +2654,27 @@ static void igb_free_all_tx_resources(struct igb_adapter *adapter) void igb_unmap_and_free_tx_resource(struct igb_ring *tx_ring, struct igb_buffer *buffer_info) { - buffer_info->dma = 0; + if (buffer_info->dma) { + if (buffer_info->mapped_as_page) + pci_unmap_page(tx_ring->pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); + else + pci_unmap_single(tx_ring->pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } if (buffer_info->skb) { - skb_dma_unmap(&tx_ring->pdev->dev, - buffer_info->skb, - DMA_TO_DEVICE); dev_kfree_skb_any(buffer_info->skb); buffer_info->skb = NULL; } buffer_info->time_stamp = 0; - /* buffer_info must be completely set up in the transmit path */ + buffer_info->length = 0; + buffer_info->next_to_watch = 0; + buffer_info->mapped_as_page = false; } /** @@ -3561,24 +3572,19 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb, unsigned int len = skb_headlen(skb); unsigned int count = 0, i; unsigned int f; - dma_addr_t *map; i = tx_ring->next_to_use; - if (skb_dma_map(&pdev->dev, skb, DMA_TO_DEVICE)) { - dev_err(&pdev->dev, "TX DMA map failed\n"); - return 0; - } - - map = skb_shinfo(skb)->dma_maps; - buffer_info = &tx_ring->buffer_info[i]; BUG_ON(len >= IGB_MAX_DATA_PER_TXD); buffer_info->length = len; /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = skb_shinfo(skb)->dma_head; + buffer_info->dma = pci_map_single(pdev, skb->data, len, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) + goto dma_error; for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; @@ -3595,7 +3601,15 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb, buffer_info->length = len; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[count]; + buffer_info->mapped_as_page = true; + buffer_info->dma = pci_map_page(pdev, + frag->page, + frag->page_offset, + len, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) + goto dma_error; + count++; } @@ -3603,6 +3617,29 @@ static inline int igb_tx_map_adv(struct igb_ring *tx_ring, struct sk_buff *skb, tx_ring->buffer_info[first].next_to_watch = i; return ++count; + +dma_error: + dev_err(&pdev->dev, "TX DMA map failed\n"); + + /* clear timestamp and dma mappings for failed buffer_info mapping */ + buffer_info->dma = 0; + buffer_info->time_stamp = 0; + buffer_info->length = 0; + buffer_info->next_to_watch = 0; + buffer_info->mapped_as_page = false; + count--; + + /* clear timestamp and dma mappings for remaining portion of packet */ + while (count >= 0) { + count--; + i--; + if (i < 0) + i += tx_ring->count; + buffer_info = &tx_ring->buffer_info[i]; + igb_unmap_and_free_tx_resource(tx_ring, buffer_info); + } + + return 0; } static inline void igb_tx_queue_adv(struct igb_ring *tx_ring, @@ -3755,7 +3792,7 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct sk_buff *skb, * has occured and we need to rewind the descriptor queue */ count = igb_tx_map_adv(tx_ring, skb, first); - if (count <= 0) { + if (!count) { dev_kfree_skb_any(skb); tx_ring->buffer_info[first].time_stamp = 0; tx_ring->next_to_use = first; @@ -4937,9 +4974,8 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector) tx_ring->detect_tx_hung = false; if (tx_ring->buffer_info[i].time_stamp && time_after(jiffies, tx_ring->buffer_info[i].time_stamp + - (adapter->tx_timeout_factor * HZ)) - && !(rd32(E1000_STATUS) & - E1000_STATUS_TXOFF)) { + (adapter->tx_timeout_factor * HZ)) && + !(rd32(E1000_STATUS) & E1000_STATUS_TXOFF)) { /* detected Tx unit hang */ dev_err(&tx_ring->pdev->dev, diff --git a/drivers/net/igbvf/igbvf.h b/drivers/net/igbvf/igbvf.h index 8e9b67ebbf8..3d1ee7a8478 100644 --- a/drivers/net/igbvf/igbvf.h +++ b/drivers/net/igbvf/igbvf.h @@ -117,6 +117,7 @@ struct igbvf_buffer { unsigned long time_stamp; u16 length; u16 next_to_watch; + u16 mapped_as_page; }; /* Rx */ struct { diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c index e01f44597a2..a127620dc65 100644 --- a/drivers/net/igbvf/netdev.c +++ b/drivers/net/igbvf/netdev.c @@ -366,10 +366,20 @@ next_desc: static void igbvf_put_txbuf(struct igbvf_adapter *adapter, struct igbvf_buffer *buffer_info) { - buffer_info->dma = 0; + if (buffer_info->dma) { + if (buffer_info->mapped_as_page) + pci_unmap_page(adapter->pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); + else + pci_unmap_single(adapter->pdev, + buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } if (buffer_info->skb) { - skb_dma_unmap(&adapter->pdev->dev, buffer_info->skb, - DMA_TO_DEVICE); dev_kfree_skb_any(buffer_info->skb); buffer_info->skb = NULL; } @@ -817,8 +827,8 @@ static bool igbvf_clean_tx_irq(struct igbvf_ring *tx_ring) adapter->detect_tx_hung = false; if (tx_ring->buffer_info[i].time_stamp && time_after(jiffies, tx_ring->buffer_info[i].time_stamp + - (adapter->tx_timeout_factor * HZ)) - && !(er32(STATUS) & E1000_STATUS_TXOFF)) { + (adapter->tx_timeout_factor * HZ)) && + !(er32(STATUS) & E1000_STATUS_TXOFF)) { tx_desc = IGBVF_TX_DESC_ADV(*tx_ring, i); /* detected Tx unit hang */ @@ -2088,27 +2098,24 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter, unsigned int first) { struct igbvf_buffer *buffer_info; + struct pci_dev *pdev = adapter->pdev; unsigned int len = skb_headlen(skb); unsigned int count = 0, i; unsigned int f; - dma_addr_t *map; i = tx_ring->next_to_use; - if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) { - dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); - return 0; - } - - map = skb_shinfo(skb)->dma_maps; - buffer_info = &tx_ring->buffer_info[i]; BUG_ON(len >= IGBVF_MAX_DATA_PER_TXD); buffer_info->length = len; /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = skb_shinfo(skb)->dma_head; + buffer_info->dma = pci_map_single(pdev, skb->data, len, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) + goto dma_error; + for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; @@ -2125,14 +2132,44 @@ static inline int igbvf_tx_map_adv(struct igbvf_adapter *adapter, buffer_info->length = len; buffer_info->time_stamp = jiffies; buffer_info->next_to_watch = i; - buffer_info->dma = map[count]; + buffer_info->mapped_as_page = true; + buffer_info->dma = pci_map_page(pdev, + frag->page, + frag->page_offset, + len, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) + goto dma_error; count++; } tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; - return count + 1; + return ++count; + +dma_error: + dev_err(&pdev->dev, "TX DMA map failed\n"); + + /* clear timestamp and dma mappings for failed buffer_info mapping */ + buffer_info->dma = 0; + buffer_info->time_stamp = 0; + buffer_info->length = 0; + buffer_info->next_to_watch = 0; + buffer_info->mapped_as_page = false; + count--; + + /* clear timestamp and dma mappings for remaining portion of packet */ + while (count >= 0) { + count--; + i--; + if (i < 0) + i += tx_ring->count; + buffer_info = &tx_ring->buffer_info[i]; + igbvf_put_txbuf(adapter, buffer_info); + } + + return 0; } static inline void igbvf_tx_queue_adv(struct igbvf_adapter *adapter, diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index ae6eab3e5ee..e8e33bb9d87 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -1124,11 +1124,11 @@ static int stir421x_patch_device(struct irda_usb_cb *self) * The actual image starts after the "STMP" keyword * so forward to the firmware header tag */ - for (i = 0; (fw->data[i] != STIR421X_PATCH_END_OF_HDR_TAG) - && (i < fw->size); i++) ; + for (i = 0; (fw->data[i] != STIR421X_PATCH_END_OF_HDR_TAG) && + (i < fw->size); i++) ; /* here we check for the out of buffer case */ - if ((STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i]) - && (i < STIR421X_PATCH_CODE_OFFSET)) { + if ((STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i]) && + (i < STIR421X_PATCH_CODE_OFFSET)) { if (!memcmp(fw->data + i + 1, STIR421X_PATCH_STMP_TAG, sizeof(STIR421X_PATCH_STMP_TAG) - 1)) { diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 528767dec9d..e5698fa30a4 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -612,16 +612,16 @@ static int fifo_txwait(struct stir_cb *stir, int space) pr_debug("fifo status 0x%lx count %lu\n", status, count); /* is fifo receiving already, or empty */ - if (!(status & FIFOCTL_DIR) - || (status & FIFOCTL_EMPTY)) + if (!(status & FIFOCTL_DIR) || + (status & FIFOCTL_EMPTY)) return 0; if (signal_pending(current)) return -EINTR; /* shutting down? */ - if (!netif_running(stir->netdev) - || !netif_device_present(stir->netdev)) + if (!netif_running(stir->netdev) || + !netif_device_present(stir->netdev)) return -ESHUTDOWN; /* only waiting for some space */ @@ -776,8 +776,8 @@ static int stir_transmit_thread(void *arg) } /* nothing to send? start receiving */ - if (!stir->receiving - && irda_device_txqueue_empty(dev)) { + if (!stir->receiving && + irda_device_txqueue_empty(dev)) { /* Wait otherwise chip gets confused. */ if (fifo_txwait(stir, -1)) break; diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index a5ca71cec02..fddb4efd545 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -1185,8 +1185,8 @@ F01_E */ * if frame size,data ptr,or skb ptr are wrong ,the get next * entry. */ - if ((skb == NULL) || (skb->data == NULL) - || (self->rx_buff.data == NULL) || (len < 6)) { + if ((skb == NULL) || (skb->data == NULL) || + (self->rx_buff.data == NULL) || (len < 6)) { self->netdev->stats.rx_dropped++; return TRUE; } @@ -1284,8 +1284,8 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) self->RetryCount++; if ((self->RetryCount >= 1) || - ((st_fifo->pending_bytes + 2048) > self->rx_buff.truesize) - || (st_fifo->len >= (MAX_RX_WINDOW))) { + ((st_fifo->pending_bytes + 2048) > self->rx_buff.truesize) || + (st_fifo->len >= (MAX_RX_WINDOW))) { while (st_fifo->len > 0) { //upload frame // Put this entry back in fifo if (st_fifo->head > MAX_RX_WINDOW) @@ -1300,8 +1300,8 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) * if frame size, data ptr, or skb ptr are wrong, * then get next entry. */ - if ((skb == NULL) || (skb->data == NULL) - || (self->rx_buff.data == NULL) || (len < 6)) { + if ((skb == NULL) || (skb->data == NULL) || + (self->rx_buff.data == NULL) || (len < 6)) { self->netdev->stats.rx_dropped++; continue; } @@ -1332,8 +1332,8 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) * if frame is receive complete at this routine ,then upload * frame. */ - if ((GetRXStatus(iobase) & 0x10) - && (RxCurCount(iobase, self) != self->RxLastCount)) { + if ((GetRXStatus(iobase) & 0x10) && + (RxCurCount(iobase, self) != self->RxLastCount)) { upload_rxdata(self, iobase); if (irda_device_txqueue_empty(self->netdev)) via_ircc_dma_receive(self); diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 7cfb8b6593c..bd3c6b5ee76 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -431,8 +431,8 @@ static struct vlsi_ring *vlsi_alloc_ring(struct pci_dev *pdev, struct ring_descr memset(rd, 0, sizeof(*rd)); rd->hw = hwmap + i; rd->buf = kmalloc(len, GFP_KERNEL|GFP_DMA); - if (rd->buf == NULL - || !(busaddr = pci_map_single(pdev, rd->buf, len, dir))) { + if (rd->buf == NULL || + !(busaddr = pci_map_single(pdev, rd->buf, len, dir))) { if (rd->buf) { IRDA_ERROR("%s: failed to create PCI-MAP for %p", __func__, rd->buf); @@ -955,8 +955,8 @@ static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb, } for(;;) { do_gettimeofday(&now); - if (now.tv_sec > ready.tv_sec - || (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec)) + if (now.tv_sec > ready.tv_sec || + (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec)) break; udelay(100); /* must not sleep here - called under netif_tx_lock! */ @@ -1594,8 +1594,8 @@ static int vlsi_irda_init(struct net_device *ndev) * see include file for details why we need these 2 masks, in this order! */ - if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW) - || pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) { + if (pci_set_dma_mask(pdev,DMA_MASK_USED_BY_HW) || + pci_set_dma_mask(pdev,DMA_MASK_MSTRPAGE)) { IRDA_ERROR("%s: aborting due to PCI BM-DMA address limitations\n", __func__); return -1; } @@ -1641,8 +1641,8 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) IRDA_MESSAGE("%s: IrDA PCI controller %s detected\n", drivername, pci_name(pdev)); - if ( !pci_resource_start(pdev,0) - || !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) { + if ( !pci_resource_start(pdev,0) || + !(pci_resource_flags(pdev,0) & IORESOURCE_IO) ) { IRDA_ERROR("%s: bar 0 invalid", __func__); goto out_disable; } diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 0e71e2a9316..04d0502726c 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -214,9 +214,9 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) * contains the manufacturer's unique code. That might be a good probe * method. Ideally you would add additional checks. */ - if (inb(ioaddr + 0) != SA_ADDR0 - || inb(ioaddr + 1) != SA_ADDR1 - || inb(ioaddr + 2) != SA_ADDR2) + if (inb(ioaddr + 0) != SA_ADDR0 || + inb(ioaddr + 1) != SA_ADDR1 || + inb(ioaddr + 2) != SA_ADDR2) goto out; if (net_debug && version_printed++ == 0) diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index aa7286bc436..49997194bdd 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -604,10 +604,10 @@ static int veth_process_caps(struct veth_lpar_connection *cnx) /* Convert timer to jiffies */ cnx->ack_timeout = remote_caps->ack_timeout * HZ / 1000000; - if ( (remote_caps->num_buffers == 0) - || (remote_caps->ack_threshold > VETH_MAX_ACKS_PER_MSG) - || (remote_caps->ack_threshold == 0) - || (cnx->ack_timeout == 0) ) { + if ( (remote_caps->num_buffers == 0) || + (remote_caps->ack_threshold > VETH_MAX_ACKS_PER_MSG) || + (remote_caps->ack_threshold == 0) || + (cnx->ack_timeout == 0) ) { veth_error("Received incompatible capabilities from LPAR %d.\n", cnx->remote_lp); return HvLpEvent_Rc_InvalidSubtypeData; @@ -714,8 +714,8 @@ static void veth_statemachine(struct work_struct *work) cnx->state |= VETH_STATE_OPEN; } - if ( (cnx->state & VETH_STATE_OPEN) - && !(cnx->state & VETH_STATE_SENTMON) ) { + if ( (cnx->state & VETH_STATE_OPEN) && + !(cnx->state & VETH_STATE_SENTMON) ) { rc = veth_signalevent(cnx, VETH_EVENT_MONITOR, HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_DeferredAck, @@ -724,8 +724,8 @@ static void veth_statemachine(struct work_struct *work) if (rc == HvLpEvent_Rc_Good) { cnx->state |= VETH_STATE_SENTMON; } else { - if ( (rc != HvLpEvent_Rc_PartitionDead) - && (rc != HvLpEvent_Rc_PathClosed) ) + if ( (rc != HvLpEvent_Rc_PartitionDead) && + (rc != HvLpEvent_Rc_PathClosed) ) veth_error("Error sending monitor to LPAR %d, " "rc = %d\n", rlp, rc); @@ -735,8 +735,8 @@ static void veth_statemachine(struct work_struct *work) } } - if ( (cnx->state & VETH_STATE_OPEN) - && !(cnx->state & VETH_STATE_SENTCAPS)) { + if ( (cnx->state & VETH_STATE_OPEN) && + !(cnx->state & VETH_STATE_SENTCAPS)) { u64 *rawcap = (u64 *)&cnx->local_caps; rc = veth_signalevent(cnx, VETH_EVENT_CAP, @@ -748,8 +748,8 @@ static void veth_statemachine(struct work_struct *work) if (rc == HvLpEvent_Rc_Good) { cnx->state |= VETH_STATE_SENTCAPS; } else { - if ( (rc != HvLpEvent_Rc_PartitionDead) - && (rc != HvLpEvent_Rc_PathClosed) ) + if ( (rc != HvLpEvent_Rc_PartitionDead) && + (rc != HvLpEvent_Rc_PathClosed) ) veth_error("Error sending caps to LPAR %d, " "rc = %d\n", rlp, rc); @@ -759,8 +759,8 @@ static void veth_statemachine(struct work_struct *work) } } - if ((cnx->state & VETH_STATE_GOTCAPS) - && !(cnx->state & VETH_STATE_SENTCAPACK)) { + if ((cnx->state & VETH_STATE_GOTCAPS) && + !(cnx->state & VETH_STATE_SENTCAPACK)) { struct veth_cap_data *remote_caps = &cnx->remote_caps; memcpy(remote_caps, &cnx->cap_event.u.caps_data, @@ -783,9 +783,9 @@ static void veth_statemachine(struct work_struct *work) goto cant_cope; } - if ((cnx->state & VETH_STATE_GOTCAPACK) - && (cnx->state & VETH_STATE_GOTCAPS) - && !(cnx->state & VETH_STATE_READY)) { + if ((cnx->state & VETH_STATE_GOTCAPACK) && + (cnx->state & VETH_STATE_GOTCAPS) && + !(cnx->state & VETH_STATE_READY)) { if (cnx->cap_ack_event.base_event.xRc == HvLpEvent_Rc_Good) { /* Start the ACK timer */ cnx->ack_timer.expires = jiffies + cnx->ack_timeout; @@ -818,8 +818,8 @@ static int veth_init_connection(u8 rlp) struct veth_msg *msgs; int i; - if ( (rlp == this_lp) - || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) ) + if ( (rlp == this_lp) || + ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) ) return 0; cnx = kzalloc(sizeof(*cnx), GFP_KERNEL); @@ -1538,8 +1538,8 @@ static void veth_receive(struct veth_lpar_connection *cnx, cnx->pending_acks[cnx->num_pending_acks++] = event->base_event.xCorrelationToken; - if ( (cnx->num_pending_acks >= cnx->remote_caps.ack_threshold) - || (cnx->num_pending_acks >= VETH_MAX_ACKS_PER_MSG) ) + if ( (cnx->num_pending_acks >= cnx->remote_caps.ack_threshold) || + (cnx->num_pending_acks >= VETH_MAX_ACKS_PER_MSG) ) veth_flush_acks(cnx); spin_unlock_irqrestore(&cnx->lock, flags); diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index e95d9b6f1f2..5257ae08b9f 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -117,6 +117,7 @@ struct ixgb_buffer { unsigned long time_stamp; u16 length; u16 next_to_watch; + u16 mapped_as_page; }; struct ixgb_desc_ring { diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 73646062e8d..bcd0f01d5fe 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -892,10 +892,18 @@ static void ixgb_unmap_and_free_tx_resource(struct ixgb_adapter *adapter, struct ixgb_buffer *buffer_info) { - buffer_info->dma = 0; + if (buffer_info->dma) { + if (buffer_info->mapped_as_page) + pci_unmap_page(adapter->pdev, buffer_info->dma, + buffer_info->length, PCI_DMA_TODEVICE); + else + pci_unmap_single(adapter->pdev, buffer_info->dma, + buffer_info->length, + PCI_DMA_TODEVICE); + buffer_info->dma = 0; + } + if (buffer_info->skb) { - skb_dma_unmap(&adapter->pdev->dev, buffer_info->skb, - DMA_TO_DEVICE); dev_kfree_skb_any(buffer_info->skb); buffer_info->skb = NULL; } @@ -1272,24 +1280,16 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, unsigned int first) { struct ixgb_desc_ring *tx_ring = &adapter->tx_ring; + struct pci_dev *pdev = adapter->pdev; struct ixgb_buffer *buffer_info; int len = skb_headlen(skb); unsigned int offset = 0, size, count = 0, i; unsigned int mss = skb_shinfo(skb)->gso_size; - unsigned int nr_frags = skb_shinfo(skb)->nr_frags; unsigned int f; - dma_addr_t *map; i = tx_ring->next_to_use; - if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) { - dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); - return 0; - } - - map = skb_shinfo(skb)->dma_maps; - while (len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, IXGB_MAX_DATA_PER_TXD); @@ -1301,11 +1301,11 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, buffer_info->length = size; WARN_ON(buffer_info->dma != 0); buffer_info->time_stamp = jiffies; - buffer_info->dma = skb_shinfo(skb)->dma_head + offset; - pci_map_single(adapter->pdev, - skb->data + offset, - size, - PCI_DMA_TODEVICE); + buffer_info->mapped_as_page = false; + buffer_info->dma = pci_map_single(pdev, skb->data + offset, + size, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) + goto dma_error; buffer_info->next_to_watch = 0; len -= size; @@ -1323,7 +1323,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, frag = &skb_shinfo(skb)->frags[f]; len = frag->size; - offset = 0; + offset = frag->page_offset; while (len) { i++; @@ -1341,7 +1341,13 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, buffer_info->length = size; buffer_info->time_stamp = jiffies; - buffer_info->dma = map[f] + offset; + buffer_info->mapped_as_page = true; + buffer_info->dma = + pci_map_page(pdev, frag->page, + offset, size, + PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, buffer_info->dma)) + goto dma_error; buffer_info->next_to_watch = 0; len -= size; @@ -1353,6 +1359,22 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb, tx_ring->buffer_info[first].next_to_watch = i; return count; + +dma_error: + dev_err(&pdev->dev, "TX DMA map failed\n"); + buffer_info->dma = 0; + count--; + + while (count >= 0) { + count--; + i--; + if (i < 0) + i += tx_ring->count; + buffer_info = &tx_ring->buffer_info[i]; + ixgb_unmap_and_free_tx_resource(adapter, buffer_info); + } + + return 0; } static void diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 76b052fa364..8da8eb53508 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -51,11 +51,11 @@ __func__ , ## args))) /* TX/RX descriptor defines */ -#define IXGBE_DEFAULT_TXD 1024 +#define IXGBE_DEFAULT_TXD 512 #define IXGBE_MAX_TXD 4096 #define IXGBE_MIN_TXD 64 -#define IXGBE_DEFAULT_RXD 1024 +#define IXGBE_DEFAULT_RXD 512 #define IXGBE_MAX_RXD 4096 #define IXGBE_MIN_RXD 64 @@ -106,6 +106,7 @@ struct ixgbe_tx_buffer { unsigned long time_stamp; u16 length; u16 next_to_watch; + u16 mapped_as_page; }; struct ixgbe_rx_buffer { @@ -160,10 +161,12 @@ struct ixgbe_ring { unsigned long reinit_state; u64 rsc_count; /* stat for coalesced packets */ u64 rsc_flush; /* stats for flushed packets */ + u32 restart_queue; /* track tx queue restarts */ + u32 non_eop_descs; /* track hardware descriptor chaining */ unsigned int size; /* length in bytes */ dma_addr_t dma; /* phys. address of descriptor ring */ -}; +} ____cacheline_internodealigned_in_smp; enum ixgbe_ring_f_enum { RING_F_NONE = 0, @@ -188,7 +191,7 @@ enum ixgbe_ring_f_enum { struct ixgbe_ring_feature { int indices; int mask; -}; +} ____cacheline_internodealigned_in_smp; #define MAX_RX_QUEUES 128 #define MAX_TX_QUEUES 128 @@ -274,29 +277,25 @@ struct ixgbe_adapter { u16 eitr_high; /* TX */ - struct ixgbe_ring *tx_ring; /* One per active queue */ + struct ixgbe_ring *tx_ring ____cacheline_aligned_in_smp; /* One per active queue */ int num_tx_queues; - u64 restart_queue; - u64 hw_csum_tx_good; - u64 lsc_int; - u64 hw_tso_ctxt; - u64 hw_tso6_ctxt; u32 tx_timeout_count; bool detect_tx_hung; + u64 restart_queue; + u64 lsc_int; + /* RX */ - struct ixgbe_ring *rx_ring; /* One per active queue */ + struct ixgbe_ring *rx_ring ____cacheline_aligned_in_smp; /* One per active queue */ int num_rx_queues; u64 hw_csum_rx_error; u64 hw_rx_no_dma_resources; - u64 hw_csum_rx_good; u64 non_eop_descs; int num_msix_vectors; int max_msix_q_vectors; /* true count of q_vectors for device */ struct ixgbe_ring_feature ring_feature[RING_F_ARRAY_SIZE]; struct msix_entry *msix_entries; - u64 rx_hdr_split; u32 alloc_rx_page_failed; u32 alloc_rx_buff_failed; diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index 40ff120a9ad..688b8ca5da3 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1382,10 +1382,10 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, hw->addr_ctrl.overflow_promisc = 0; /* Zero out the other receive addresses */ - hw_dbg(hw, "Clearing RAR[1-%d]\n", uc_addr_in_use); - for (i = 1; i <= uc_addr_in_use; i++) { - IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0); - IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0); + hw_dbg(hw, "Clearing RAR[1-%d]\n", uc_addr_in_use + 1); + for (i = 0; i < uc_addr_in_use; i++) { + IXGBE_WRITE_REG(hw, IXGBE_RAL(1+i), 0); + IXGBE_WRITE_REG(hw, IXGBE_RAH(1+i), 0); } /* Add the new addresses */ @@ -1755,17 +1755,24 @@ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw) /* * On backplane, bail out if * - backplane autoneg was not completed, or if - * - link partner is not AN enabled + * - we are 82599 and link partner is not AN enabled */ if (hw->phy.media_type == ixgbe_media_type_backplane) { links = IXGBE_READ_REG(hw, IXGBE_LINKS); - links2 = IXGBE_READ_REG(hw, IXGBE_LINKS2); - if (((links & IXGBE_LINKS_KX_AN_COMP) == 0) || - ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0)) { + if ((links & IXGBE_LINKS_KX_AN_COMP) == 0) { hw->fc.fc_was_autonegged = false; hw->fc.current_mode = hw->fc.requested_mode; goto out; } + + if (hw->mac.type == ixgbe_mac_82599EB) { + links2 = IXGBE_READ_REG(hw, IXGBE_LINKS2); + if ((links2 & IXGBE_LINKS2_AN_SUPPORTED) == 0) { + hw->fc.fc_was_autonegged = false; + hw->fc.current_mode = hw->fc.requested_mode; + goto out; + } + } } /* @@ -1784,6 +1791,20 @@ s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw) } /* + * Bail out on + * - copper or CX4 adapters + * - fiber adapters running at 10gig + */ + if ((hw->phy.media_type == ixgbe_media_type_copper) || + (hw->phy.media_type == ixgbe_media_type_cx4) || + ((hw->phy.media_type == ixgbe_media_type_fiber) && + (speed == IXGBE_LINK_SPEED_10GB_FULL))) { + hw->fc.fc_was_autonegged = false; + hw->fc.current_mode = hw->fc.requested_mode; + goto out; + } + + /* * Read the AN advertisement and LP ability registers and resolve * local flow control settings accordingly */ diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 84ab4db7074..06a9d18bbdb 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -93,16 +93,11 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { {"tx_restart_queue", IXGBE_STAT(restart_queue)}, {"rx_long_length_errors", IXGBE_STAT(stats.roc)}, {"rx_short_length_errors", IXGBE_STAT(stats.ruc)}, - {"tx_tcp4_seg_ctxt", IXGBE_STAT(hw_tso_ctxt)}, - {"tx_tcp6_seg_ctxt", IXGBE_STAT(hw_tso6_ctxt)}, {"tx_flow_control_xon", IXGBE_STAT(stats.lxontxc)}, {"rx_flow_control_xon", IXGBE_STAT(stats.lxonrxc)}, {"tx_flow_control_xoff", IXGBE_STAT(stats.lxofftxc)}, {"rx_flow_control_xoff", IXGBE_STAT(stats.lxoffrxc)}, - {"rx_csum_offload_good", IXGBE_STAT(hw_csum_rx_good)}, {"rx_csum_offload_errors", IXGBE_STAT(hw_csum_rx_error)}, - {"tx_csum_offload_ctxt", IXGBE_STAT(hw_csum_tx_good)}, - {"rx_header_split", IXGBE_STAT(rx_hdr_split)}, {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, {"rx_no_dma_resources", IXGBE_STAT(hw_rx_no_dma_resources)}, @@ -205,6 +200,56 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->autoneg = AUTONEG_DISABLE; } + /* Get PHY type */ + switch (adapter->hw.phy.type) { + case ixgbe_phy_tn: + case ixgbe_phy_cu_unknown: + /* Copper 10G-BASET */ + ecmd->port = PORT_TP; + break; + case ixgbe_phy_qt: + ecmd->port = PORT_FIBRE; + break; + case ixgbe_phy_nl: + case ixgbe_phy_tw_tyco: + case ixgbe_phy_tw_unknown: + case ixgbe_phy_sfp_ftl: + case ixgbe_phy_sfp_avago: + case ixgbe_phy_sfp_intel: + case ixgbe_phy_sfp_unknown: + switch (adapter->hw.phy.sfp_type) { + /* SFP+ devices, further checking needed */ + case ixgbe_sfp_type_da_cu: + case ixgbe_sfp_type_da_cu_core0: + case ixgbe_sfp_type_da_cu_core1: + ecmd->port = PORT_DA; + break; + case ixgbe_sfp_type_sr: + case ixgbe_sfp_type_lr: + case ixgbe_sfp_type_srlr_core0: + case ixgbe_sfp_type_srlr_core1: + ecmd->port = PORT_FIBRE; + break; + case ixgbe_sfp_type_not_present: + ecmd->port = PORT_NONE; + break; + case ixgbe_sfp_type_unknown: + default: + ecmd->port = PORT_OTHER; + break; + } + break; + case ixgbe_phy_xaui: + ecmd->port = PORT_NONE; + break; + case ixgbe_phy_unknown: + case ixgbe_phy_generic: + case ixgbe_phy_sfp_unsupported: + default: + ecmd->port = PORT_OTHER; + break; + } + hw->mac.ops.check_link(hw, &link_speed, &link_up, false); if (link_up) { ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? @@ -1972,6 +2017,10 @@ static int ixgbe_get_coalesce(struct net_device *netdev, break; } + /* if in mixed tx/rx queues per vector mode, report only rx settings */ + if (adapter->q_vector[0]->txr_count && adapter->q_vector[0]->rxr_count) + return 0; + /* only valid if in constant ITR mode */ switch (adapter->tx_itr_setting) { case 0: @@ -1997,12 +2046,9 @@ static int ixgbe_set_coalesce(struct net_device *netdev, struct ixgbe_q_vector *q_vector; int i; - /* - * don't accept tx specific changes if we've got mixed RxTx vectors - * test and jump out here if needed before changing the rx numbers - */ - if ((1000000/ec->tx_coalesce_usecs) != adapter->tx_eitr_param && - adapter->q_vector[0]->txr_count && adapter->q_vector[0]->rxr_count) + /* don't accept tx specific changes if we've got mixed RxTx vectors */ + if (adapter->q_vector[0]->txr_count && adapter->q_vector[0]->rxr_count + && ec->tx_coalesce_usecs) return -EINVAL; if (ec->tx_max_coalesced_frames_irq) diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index edecdc853c1..da32a108a7b 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -499,6 +499,10 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_fcoe *fcoe = &adapter->fcoe; struct ixgbe_ring_feature *f = &adapter->ring_feature[RING_F_FCOE]; +#ifdef CONFIG_IXGBE_DCB + u8 tc; + u32 up2tc; +#endif /* create the pool for ddp if not created yet */ if (!fcoe->pool) { @@ -540,6 +544,17 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) IXGBE_FCRXCTRL_FCOELLI | IXGBE_FCRXCTRL_FCCRCBO | (FC_FCOE_VER << IXGBE_FCRXCTRL_FCOEVER_SHIFT)); +#ifdef CONFIG_IXGBE_DCB + up2tc = IXGBE_READ_REG(&adapter->hw, IXGBE_RTTUP2TC); + for (i = 0; i < MAX_USER_PRIORITY; i++) { + tc = (u8)(up2tc >> (i * IXGBE_RTTUP2TC_UP_SHIFT)); + tc &= (MAX_TRAFFIC_CLASS - 1); + if (fcoe->tc == tc) { + fcoe->up = i; + break; + } + } +#endif } /** @@ -671,19 +686,7 @@ out_disable: */ u8 ixgbe_fcoe_getapp(struct ixgbe_adapter *adapter) { - int i; - u8 tc; - u32 up2tc; - - up2tc = IXGBE_READ_REG(&adapter->hw, IXGBE_RTTUP2TC); - for (i = 0; i < MAX_USER_PRIORITY; i++) { - tc = (u8)(up2tc >> (i * IXGBE_RTTUP2TC_UP_SHIFT)); - tc &= (MAX_TRAFFIC_CLASS - 1); - if (adapter->fcoe.tc == tc) - return 1 << i; - } - - return 0; + return 1 << adapter->fcoe.up; } /** @@ -710,6 +713,7 @@ u8 ixgbe_fcoe_setapp(struct ixgbe_adapter *adapter, u8 up) up2tc >>= (i * IXGBE_RTTUP2TC_UP_SHIFT); up2tc &= (MAX_TRAFFIC_CLASS - 1); adapter->fcoe.tc = (u8)up2tc; + adapter->fcoe.up = i; return 0; } } diff --git a/drivers/net/ixgbe/ixgbe_fcoe.h b/drivers/net/ixgbe/ixgbe_fcoe.h index b5dee7b3ef1..de8ff53187d 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.h +++ b/drivers/net/ixgbe/ixgbe_fcoe.h @@ -62,7 +62,10 @@ struct ixgbe_fcoe_ddp { }; struct ixgbe_fcoe { +#ifdef CONFIG_IXGBE_DCB u8 tc; + u8 up; +#endif spinlock_t lock; struct pci_pool *pool; struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX]; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 5182b289343..247ed2a2476 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -218,10 +218,20 @@ static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, struct ixgbe_tx_buffer *tx_buffer_info) { - tx_buffer_info->dma = 0; + if (tx_buffer_info->dma) { + if (tx_buffer_info->mapped_as_page) + pci_unmap_page(adapter->pdev, + tx_buffer_info->dma, + tx_buffer_info->length, + PCI_DMA_TODEVICE); + else + pci_unmap_single(adapter->pdev, + tx_buffer_info->dma, + tx_buffer_info->length, + PCI_DMA_TODEVICE); + tx_buffer_info->dma = 0; + } if (tx_buffer_info->skb) { - skb_dma_unmap(&adapter->pdev->dev, tx_buffer_info->skb, - DMA_TO_DEVICE); dev_kfree_skb_any(tx_buffer_info->skb); tx_buffer_info->skb = NULL; } @@ -242,11 +252,11 @@ static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter, static inline bool ixgbe_tx_is_paused(struct ixgbe_adapter *adapter, struct ixgbe_ring *tx_ring) { - int tc; u32 txoff = IXGBE_TFCS_TXOFF; #ifdef CONFIG_IXGBE_DCB if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + int tc; int reg_idx = tx_ring->reg_idx; int dcb_i = adapter->ring_feature[RING_F_DCB].indices; @@ -403,7 +413,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector, if (__netif_subqueue_stopped(netdev, tx_ring->queue_index) && !test_bit(__IXGBE_DOWN, &adapter->state)) { netif_wake_subqueue(netdev, tx_ring->queue_index); - ++adapter->restart_queue; + ++tx_ring->restart_queue; } } @@ -614,7 +624,6 @@ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter, /* It must be a TCP or UDP packet with a valid checksum */ skb->ip_summed = CHECKSUM_UNNECESSARY; - adapter->hw_csum_rx_good++; } static inline void ixgbe_release_rx_desc(struct ixgbe_hw *hw, @@ -671,14 +680,19 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, if (!bi->skb) { struct sk_buff *skb; - skb = netdev_alloc_skb_ip_align(adapter->netdev, - rx_ring->rx_buf_len); + /* netdev_alloc_skb reserves 32 bytes up front!! */ + uint bufsz = rx_ring->rx_buf_len + SMP_CACHE_BYTES; + skb = netdev_alloc_skb(adapter->netdev, bufsz); if (!skb) { adapter->alloc_rx_buff_failed++; goto no_buffers; } + /* advance the data pointer to the next cache line */ + skb_reserve(skb, (PTR_ALIGN(skb->data, SMP_CACHE_BYTES) + - skb->data)); + bi->skb = skb; bi->dma = pci_map_single(pdev, skb->data, rx_ring->rx_buf_len, @@ -791,8 +805,6 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, hdr_info = le16_to_cpu(ixgbe_get_hdr_info(rx_desc)); len = (hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >> IXGBE_RXDADV_HDRBUFLEN_SHIFT; - if (hdr_info & IXGBE_RXDADV_SPH) - adapter->rx_hdr_split++; if (len > IXGBE_RX_HDR_SIZE) len = IXGBE_RX_HDR_SIZE; upper_len = le16_to_cpu(rx_desc->wb.upper.length); @@ -802,7 +814,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, cleaned = true; skb = rx_buffer_info->skb; - prefetch(skb->data - NET_IP_ALIGN); + prefetch(skb->data); rx_buffer_info->skb = NULL; if (rx_buffer_info->dma) { @@ -874,7 +886,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, skb->next = next_buffer->skb; skb->next->prev = skb; } - adapter->non_eop_descs++; + rx_ring->non_eop_descs++; goto next_desc; } @@ -1317,8 +1329,7 @@ static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data) r_idx + 1); } - /* disable interrupts on this vector only */ - ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); + /* EIAM disabled interrupts (on this vector) for us */ napi_schedule(&q_vector->napi); return IRQ_HANDLED; @@ -1350,7 +1361,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) return IRQ_HANDLED; /* disable interrupts on this vector only */ - ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); + /* EIAM disabled interrupts (on this vector) for us */ napi_schedule(&q_vector->napi); return IRQ_HANDLED; @@ -1385,8 +1396,7 @@ static irqreturn_t ixgbe_msix_clean_many(int irq, void *data) r_idx + 1); } - /* disable interrupts on this vector only */ - ixgbe_irq_disable_queues(adapter, ((u64)1 << q_vector->v_idx)); + /* EIAM disabled interrupts (on this vector) for us */ napi_schedule(&q_vector->napi); return IRQ_HANDLED; @@ -2704,7 +2714,22 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); } - if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { + /* + * use EIAM to auto-mask when MSI-X interrupt is asserted + * this saves a register write for every interrupt + */ + switch (hw->mac.type) { + case ixgbe_mac_82598EB: + IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); + break; + default: + case ixgbe_mac_82599EB: + IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF); + IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF); + break; + } + } else { /* legacy interrupts, use EIAM to auto-mask when reading EICR, * specifically only auto mask tx and rx interrupts */ IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); @@ -3948,8 +3973,10 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) adapter->flags |= IXGBE_FLAG_FCOE_CAPABLE; adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; adapter->ring_feature[RING_F_FCOE].indices = 0; +#ifdef CONFIG_IXGBE_DCB /* Default traffic class to use for FCoE */ adapter->fcoe.tc = IXGBE_FCOE_DEFTC; +#endif #endif /* IXGBE_FCOE */ } @@ -4499,6 +4526,13 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) adapter->rsc_total_flush = rsc_flush; } + /* gather some stats to the adapter struct that are per queue */ + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->restart_queue += adapter->tx_ring[i].restart_queue; + + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->non_eop_descs += adapter->tx_ring[i].non_eop_descs; + adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS); for (i = 0; i < 8; i++) { /* for packet buffers not used, the register should read 0 */ @@ -4881,14 +4915,12 @@ static int ixgbe_tso(struct ixgbe_adapter *adapter, iph->daddr, 0, IPPROTO_TCP, 0); - adapter->hw_tso_ctxt++; } else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) { ipv6_hdr(skb)->payload_len = 0; tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); - adapter->hw_tso6_ctxt++; } i = tx_ring->next_to_use; @@ -5007,7 +5039,6 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; - adapter->hw_csum_tx_good++; i++; if (i == tx_ring->count) i = 0; @@ -5024,23 +5055,16 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, struct sk_buff *skb, u32 tx_flags, unsigned int first) { + struct pci_dev *pdev = adapter->pdev; struct ixgbe_tx_buffer *tx_buffer_info; unsigned int len; unsigned int total = skb->len; unsigned int offset = 0, size, count = 0, i; unsigned int nr_frags = skb_shinfo(skb)->nr_frags; unsigned int f; - dma_addr_t *map; i = tx_ring->next_to_use; - if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) { - dev_err(&adapter->pdev->dev, "TX DMA map failed\n"); - return 0; - } - - map = skb_shinfo(skb)->dma_maps; - if (tx_flags & IXGBE_TX_FLAGS_FCOE) /* excluding fcoe_crc_eof for FCoE */ total -= sizeof(struct fcoe_crc_eof); @@ -5051,7 +5075,12 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = skb_shinfo(skb)->dma_head + offset; + tx_buffer_info->mapped_as_page = false; + tx_buffer_info->dma = pci_map_single(pdev, + skb->data + offset, + size, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pdev, tx_buffer_info->dma)) + goto dma_error; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; @@ -5072,7 +5101,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, frag = &skb_shinfo(skb)->frags[f]; len = min((unsigned int)frag->size, total); - offset = 0; + offset = frag->page_offset; while (len) { i++; @@ -5083,7 +5112,13 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD); tx_buffer_info->length = size; - tx_buffer_info->dma = map[f] + offset; + tx_buffer_info->dma = pci_map_page(adapter->pdev, + frag->page, + offset, size, + PCI_DMA_TODEVICE); + tx_buffer_info->mapped_as_page = true; + if (pci_dma_mapping_error(pdev, tx_buffer_info->dma)) + goto dma_error; tx_buffer_info->time_stamp = jiffies; tx_buffer_info->next_to_watch = i; @@ -5100,6 +5135,27 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter, tx_ring->tx_buffer_info[first].next_to_watch = i; return count; + +dma_error: + dev_err(&pdev->dev, "TX DMA map failed\n"); + + /* clear timestamp and dma mappings for failed tx_buffer_info map */ + tx_buffer_info->dma = 0; + tx_buffer_info->time_stamp = 0; + tx_buffer_info->next_to_watch = 0; + count--; + + /* clear timestamp and dma mappings for remaining portion of packet */ + while (count >= 0) { + count--; + i--; + if (i < 0) + i += tx_ring->count; + tx_buffer_info = &tx_ring->tx_buffer_info[i]; + ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info); + } + + return count; } static void ixgbe_tx_queue(struct ixgbe_adapter *adapter, @@ -5219,8 +5275,6 @@ static void ixgbe_atr(struct ixgbe_adapter *adapter, struct sk_buff *skb, static int __ixgbe_maybe_stop_tx(struct net_device *netdev, struct ixgbe_ring *tx_ring, int size) { - struct ixgbe_adapter *adapter = netdev_priv(netdev); - netif_stop_subqueue(netdev, tx_ring->queue_index); /* Herbert's original patch had: * smp_mb__after_netif_stop_queue(); @@ -5234,7 +5288,7 @@ static int __ixgbe_maybe_stop_tx(struct net_device *netdev, /* A reprieve! - use start_queue because it doesn't call schedule */ netif_start_subqueue(netdev, tx_ring->queue_index); - ++adapter->restart_queue; + ++tx_ring->restart_queue; return 0; } @@ -5249,10 +5303,19 @@ static int ixgbe_maybe_stop_tx(struct net_device *netdev, static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) { struct ixgbe_adapter *adapter = netdev_priv(dev); + int txq = smp_processor_id(); if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) - return smp_processor_id(); + return txq; +#ifdef IXGBE_FCOE + if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && + (skb->protocol == htons(ETH_P_FCOE))) { + txq &= (adapter->ring_feature[RING_F_FCOE].indices - 1); + txq += adapter->ring_feature[RING_F_FCOE].mask; + return txq; + } +#endif if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) return (skb->vlan_tci & IXGBE_TX_FLAGS_VLAN_PRIO_MASK) >> 13; @@ -5267,7 +5330,7 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, unsigned int first; unsigned int tx_flags = 0; u8 hdr_len = 0; - int r_idx = 0, tso; + int tso; int count = 0; unsigned int f; @@ -5275,13 +5338,13 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, tx_flags |= vlan_tx_tag_get(skb); if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { tx_flags &= ~IXGBE_TX_FLAGS_VLAN_PRIO_MASK; - tx_flags |= (skb->queue_mapping << 13); + tx_flags |= ((skb->queue_mapping & 0x7) << 13); } tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_VLAN; } else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { if (skb->priority != TC_PRIO_CONTROL) { - tx_flags |= (skb->queue_mapping << 13); + tx_flags |= ((skb->queue_mapping & 0x7) << 13); tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_VLAN; } else { @@ -5290,17 +5353,18 @@ static netdev_tx_t ixgbe_xmit_frame(struct sk_buff *skb, } } - r_idx = skb->queue_mapping; - tx_ring = &adapter->tx_ring[r_idx]; + tx_ring = &adapter->tx_ring[skb->queue_mapping]; if ((adapter->flags & IXGBE_FLAG_FCOE_ENABLED) && (skb->protocol == htons(ETH_P_FCOE))) { tx_flags |= IXGBE_TX_FLAGS_FCOE; #ifdef IXGBE_FCOE - r_idx = smp_processor_id(); - r_idx &= (adapter->ring_feature[RING_F_FCOE].indices - 1); - r_idx += adapter->ring_feature[RING_F_FCOE].mask; - tx_ring = &adapter->tx_ring[r_idx]; +#ifdef CONFIG_IXGBE_DCB + tx_flags &= ~(IXGBE_TX_FLAGS_VLAN_PRIO_MASK + << IXGBE_TX_FLAGS_VLAN_SHIFT); + tx_flags |= ((adapter->fcoe.up << 13) + << IXGBE_TX_FLAGS_VLAN_SHIFT); +#endif #endif } /* four things can cause us to need a context descriptor */ diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 35d5bed450d..f47d4d663b1 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -130,8 +130,8 @@ static int __devinit sonic_probe1(struct net_device *dev) printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision); i = 0; - while (known_revisions[i] != 0xffff - && known_revisions[i] != silicon_revision) + while (known_revisions[i] != 0xffff && + known_revisions[i] != silicon_revision) i++; if (known_revisions[i] == 0xffff) { diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 6c1b92fa0b0..792b88fc357 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -1050,8 +1050,8 @@ jme_dynamic_pcc(struct jme_adapter *jme) if ((NET_STAT(jme).rx_bytes - dpi->last_bytes) > PCC_P3_THRESHOLD) jme_attempt_pcc(dpi, PCC_P3); - else if ((NET_STAT(jme).rx_packets - dpi->last_pkts) > PCC_P2_THRESHOLD - || dpi->intr_cnt > PCC_INTR_THRESHOLD) + else if ((NET_STAT(jme).rx_packets - dpi->last_pkts) > PCC_P2_THRESHOLD || + dpi->intr_cnt > PCC_INTR_THRESHOLD) jme_attempt_pcc(dpi, PCC_P2); else jme_attempt_pcc(dpi, PCC_P1); @@ -2199,8 +2199,8 @@ jme_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd) if (netif_running(netdev)) return -EBUSY; - if (ecmd->use_adaptive_rx_coalesce - && test_bit(JME_FLAG_POLL, &jme->flags)) { + if (ecmd->use_adaptive_rx_coalesce && + test_bit(JME_FLAG_POLL, &jme->flags)) { clear_bit(JME_FLAG_POLL, &jme->flags); jme->jme_rx = netif_rx; jme->jme_vlan_rx = vlan_hwaccel_rx; @@ -2209,8 +2209,8 @@ jme_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd) dpi->cnt = 0; jme_set_rx_pcc(jme, PCC_P1); jme_interrupt_mode(jme); - } else if (!(ecmd->use_adaptive_rx_coalesce) - && !(test_bit(JME_FLAG_POLL, &jme->flags))) { + } else if (!(ecmd->use_adaptive_rx_coalesce) && + !(test_bit(JME_FLAG_POLL, &jme->flags))) { set_bit(JME_FLAG_POLL, &jme->flags); jme->jme_rx = netif_receive_skb; jme->jme_vlan_rx = vlan_hwaccel_receive_skb; diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index a23f739d222..6d3ac65bc35 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -1,4 +1,4 @@ -/* drivers/net/ks8651.c +/* drivers/net/ks8851.c * * Copyright 2009 Simtec Electronics * http://www.simtec.co.uk/ @@ -714,7 +714,7 @@ static void ks8851_tx_work(struct work_struct *work) { struct ks8851_net *ks = container_of(work, struct ks8851_net, tx_work); struct sk_buff *txb; - bool last = false; + bool last = skb_queue_empty(&ks->txq); mutex_lock(&ks->lock); diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 0be14d702be..c146304d8d6 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -568,6 +568,16 @@ static inline void ks_outblk(struct ks_net *ks, u16 *wptr, u32 len) iowrite16(*wptr++, ks->hw_addr); } +static void ks_disable_int(struct ks_net *ks) +{ + ks_wrreg16(ks, KS_IER, 0x0000); +} /* ks_disable_int */ + +static void ks_enable_int(struct ks_net *ks) +{ + ks_wrreg16(ks, KS_IER, ks->rc_ier); +} /* ks_enable_int */ + /** * ks_tx_fifo_space - return the available hardware buffer size. * @ks: The chip information @@ -681,6 +691,47 @@ static void ks_soft_reset(struct ks_net *ks, unsigned op) } +void ks_enable_qmu(struct ks_net *ks) +{ + u16 w; + + w = ks_rdreg16(ks, KS_TXCR); + /* Enables QMU Transmit (TXCR). */ + ks_wrreg16(ks, KS_TXCR, w | TXCR_TXE); + + /* + * RX Frame Count Threshold Enable and Auto-Dequeue RXQ Frame + * Enable + */ + + w = ks_rdreg16(ks, KS_RXQCR); + ks_wrreg16(ks, KS_RXQCR, w | RXQCR_RXFCTE); + + /* Enables QMU Receive (RXCR1). */ + w = ks_rdreg16(ks, KS_RXCR1); + ks_wrreg16(ks, KS_RXCR1, w | RXCR1_RXE); + ks->enabled = true; +} /* ks_enable_qmu */ + +static void ks_disable_qmu(struct ks_net *ks) +{ + u16 w; + + w = ks_rdreg16(ks, KS_TXCR); + + /* Disables QMU Transmit (TXCR). */ + w &= ~TXCR_TXE; + ks_wrreg16(ks, KS_TXCR, w); + + /* Disables QMU Receive (RXCR1). */ + w = ks_rdreg16(ks, KS_RXCR1); + w &= ~RXCR1_RXE ; + ks_wrreg16(ks, KS_RXCR1, w); + + ks->enabled = false; + +} /* ks_disable_qmu */ + /** * ks_read_qmu - read 1 pkt data from the QMU. * @ks: The chip information @@ -752,7 +803,7 @@ static void ks_rcv(struct ks_net *ks, struct net_device *netdev) (frame_hdr->len < RX_BUF_SIZE) && frame_hdr->len)) { skb_reserve(skb, 2); /* read data block including CRC 4 bytes */ - ks_read_qmu(ks, (u16 *)skb->data, frame_hdr->len + 4); + ks_read_qmu(ks, (u16 *)skb->data, frame_hdr->len); skb_put(skb, frame_hdr->len); skb->dev = netdev; skb->protocol = eth_type_trans(skb, netdev); @@ -861,7 +912,7 @@ static int ks_net_open(struct net_device *netdev) ks_dbg(ks, "%s - entry\n", __func__); /* reset the HW */ - err = request_irq(ks->irq, ks_irq, KS_INT_FLAGS, DRV_NAME, ks); + err = request_irq(ks->irq, ks_irq, KS_INT_FLAGS, DRV_NAME, netdev); if (err) { printk(KERN_ERR "Failed to request IRQ: %d: %d\n", @@ -869,6 +920,15 @@ static int ks_net_open(struct net_device *netdev) return err; } + /* wake up powermode to normal mode */ + ks_set_powermode(ks, PMECR_PM_NORMAL); + mdelay(1); /* wait for normal mode to take effect */ + + ks_wrreg16(ks, KS_ISR, 0xffff); + ks_enable_int(ks); + ks_enable_qmu(ks); + netif_start_queue(ks->netdev); + if (netif_msg_ifup(ks)) ks_dbg(ks, "network device %s up\n", netdev->name); @@ -892,19 +952,14 @@ static int ks_net_stop(struct net_device *netdev) netif_stop_queue(netdev); - kfree(ks->frame_head_info); - mutex_lock(&ks->lock); /* turn off the IRQs and ack any outstanding */ ks_wrreg16(ks, KS_IER, 0x0000); ks_wrreg16(ks, KS_ISR, 0xffff); - /* shutdown RX process */ - ks_wrreg16(ks, KS_RXCR1, 0x0000); - - /* shutdown TX process */ - ks_wrreg16(ks, KS_TXCR, 0x0000); + /* shutdown RX/TX QMU */ + ks_disable_qmu(ks); /* set powermode to soft power down to save power */ ks_set_powermode(ks, PMECR_PM_SOFTDOWN); @@ -929,17 +984,8 @@ static int ks_net_stop(struct net_device *netdev) */ static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len) { - unsigned fid = ks->fid; - - fid = ks->fid; - ks->fid = (ks->fid + 1) & TXFR_TXFID_MASK; - - /* reduce the tx interrupt occurrances. */ - if (!fid) - fid |= TXFR_TXIC; /* irq on completion */ - /* start header at txb[0] to align txw entries */ - ks->txh.txw[0] = cpu_to_le16(fid); + ks->txh.txw[0] = 0; ks->txh.txw[1] = cpu_to_le16(len); /* 1. set sudo-DMA mode */ @@ -957,16 +1003,6 @@ static void ks_write_qmu(struct ks_net *ks, u8 *pdata, u16 len) ; } -static void ks_disable_int(struct ks_net *ks) -{ - ks_wrreg16(ks, KS_IER, 0x0000); -} /* ks_disable_int */ - -static void ks_enable_int(struct ks_net *ks) -{ - ks_wrreg16(ks, KS_IER, ks->rc_ier); -} /* ks_enable_int */ - /** * ks_start_xmit - transmit packet * @skb : The buffer to transmit @@ -1410,25 +1446,6 @@ static int ks_read_selftest(struct ks_net *ks) return ret; } -static void ks_disable(struct ks_net *ks) -{ - u16 w; - - w = ks_rdreg16(ks, KS_TXCR); - - /* Disables QMU Transmit (TXCR). */ - w &= ~TXCR_TXE; - ks_wrreg16(ks, KS_TXCR, w); - - /* Disables QMU Receive (RXCR1). */ - w = ks_rdreg16(ks, KS_RXCR1); - w &= ~RXCR1_RXE ; - ks_wrreg16(ks, KS_RXCR1, w); - - ks->enabled = false; - -} /* ks_disable */ - static void ks_setup(struct ks_net *ks) { u16 w; @@ -1463,7 +1480,7 @@ static void ks_setup(struct ks_net *ks) w = TXCR_TXFCE | TXCR_TXPE | TXCR_TXCRC | TXCR_TCGIP; ks_wrreg16(ks, KS_TXCR, w); - w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE; + w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE | RXCR1_RXME | RXCR1_RXIPFCC; if (ks->promiscuous) /* bPromiscuous */ w |= (RXCR1_RXAE | RXCR1_RXINVF); @@ -1486,28 +1503,6 @@ static void ks_setup_int(struct ks_net *ks) ks->rc_ier = (IRQ_LCI | IRQ_TXI | IRQ_RXI); } /* ks_setup_int */ -void ks_enable(struct ks_net *ks) -{ - u16 w; - - w = ks_rdreg16(ks, KS_TXCR); - /* Enables QMU Transmit (TXCR). */ - ks_wrreg16(ks, KS_TXCR, w | TXCR_TXE); - - /* - * RX Frame Count Threshold Enable and Auto-Dequeue RXQ Frame - * Enable - */ - - w = ks_rdreg16(ks, KS_RXQCR); - ks_wrreg16(ks, KS_RXQCR, w | RXQCR_RXFCTE); - - /* Enables QMU Receive (RXCR1). */ - w = ks_rdreg16(ks, KS_RXCR1); - ks_wrreg16(ks, KS_RXCR1, w | RXCR1_RXE); - ks->enabled = true; -} /* ks_enable */ - static int ks_hw_init(struct ks_net *ks) { #define MHEADER_SIZE (sizeof(struct type_frame_head) * MAX_RECV_FRAMES) @@ -1612,11 +1607,9 @@ static int __devinit ks8851_probe(struct platform_device *pdev) ks_soft_reset(ks, GRR_GSR); ks_hw_init(ks); - ks_disable(ks); + ks_disable_qmu(ks); ks_setup(ks); ks_setup_int(ks); - ks_enable_int(ks); - ks_enable(ks); memcpy(netdev->dev_addr, ks->mac_addr, 6); data = ks_rdreg16(ks, KS_OBCR); @@ -1658,6 +1651,7 @@ static int __devexit ks8851_remove(struct platform_device *pdev) struct ks_net *ks = netdev_priv(netdev); struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + kfree(ks->frame_head_info); unregister_netdev(netdev); iounmap(ks->hw_addr); free_netdev(netdev); diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 7b2c42992c3..8d7d3d4625f 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -493,14 +493,14 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int static const short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360}; int hp_port = (readl(bios + 1) & 1) ? 0x499 : 0x99; /* We can have boards other than the built-in! Verify this is on-board. */ - if ((inb(hp_port) & 0xc0) == 0x80 - && ioaddr_table[inb(hp_port) & 3] == ioaddr) + if ((inb(hp_port) & 0xc0) == 0x80 && + ioaddr_table[inb(hp_port) & 3] == ioaddr) hp_builtin = hp_port; } iounmap(bios); /* We also recognize the HP Vectra on-board here, but check below. */ - hpJ2405A = (inb(ioaddr) == 0x08 && inb(ioaddr+1) == 0x00 - && inb(ioaddr+2) == 0x09); + hpJ2405A = (inb(ioaddr) == 0x08 && inb(ioaddr+1) == 0x00 && + inb(ioaddr+2) == 0x09); /* Reset the LANCE. */ reset_val = inw(ioaddr+LANCE_RESET); /* Reset the LANCE */ @@ -1035,8 +1035,8 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id) spin_lock (&lp->devlock); outw(0x00, dev->base_addr + LANCE_ADDR); - while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600 - && --boguscnt >= 0) { + while ((csr0 = inw(dev->base_addr + LANCE_DATA)) & 0x8600 && + --boguscnt >= 0) { /* Acknowledge all of the current interrupt sources ASAP. */ outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA); diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index 256119882b1..57f25848fe8 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -464,8 +464,8 @@ static irqreturn_t __ei_interrupt(int irq, void *dev_id) ei_inb_p(e8390_base + EN0_ISR)); /* !!Assumption!! -- we stay in page 0. Don't break this. */ - while ((interrupts = ei_inb_p(e8390_base + EN0_ISR)) != 0 - && ++nr_serviced < MAX_SERVICE) + while ((interrupts = ei_inb_p(e8390_base + EN0_ISR)) != 0 && + ++nr_serviced < MAX_SERVICE) { if (!netif_running(dev)) { printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name); @@ -721,10 +721,10 @@ static void ei_receive(struct net_device *dev) /* Check for bogosity warned by 3c503 book: the status byte is never written. This happened a lot during testing! This code should be cleaned up someday. */ - if (rx_frame.next != next_frame - && rx_frame.next != next_frame + 1 - && rx_frame.next != next_frame - num_rx_pages - && rx_frame.next != next_frame + 1 - num_rx_pages) { + if (rx_frame.next != next_frame && + rx_frame.next != next_frame + 1 && + rx_frame.next != next_frame - num_rx_pages && + rx_frame.next != next_frame + 1 - num_rx_pages) { ei_local->current_page = rxing_page; ei_outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY); dev->stats.rx_errors++; diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index f2a197fd47a..336e7c7a927 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -231,8 +231,8 @@ static void temac_set_multicast_list(struct net_device *ndev) int i; mutex_lock(&lp->indirect_mutex); - if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) - || ndev->mc_count > MULTICAST_CAM_TABLE_NUM) { + if (ndev->flags & (IFF_ALLMULTI | IFF_PROMISC) || + ndev->mc_count > MULTICAST_CAM_TABLE_NUM) { /* * We must make the kernel realise we had to move * into promisc mode or we start all out war on diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 1bc654a73c4..eae4ad749e9 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -207,20 +207,12 @@ static __net_init int loopback_net_init(struct net *net) out_free_netdev: free_netdev(dev); out: - if (net == &init_net) + if (net_eq(net, &init_net)) panic("loopback: Failed to register netdevice: %d\n", err); return err; } -static __net_exit void loopback_net_exit(struct net *net) -{ - struct net_device *dev = net->loopback_dev; - - unregister_netdev(dev); -} - /* Registered in net/core/dev.c */ struct pernet_operations __net_initdata loopback_net_ops = { .init = loopback_net_init, - .exit = loopback_net_exit, }; diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index c244ec34fc4..23b633e2ac4 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -222,8 +222,8 @@ struct net_device * __init mac89x0_probe(int unit) int card_present; local_irq_save(flags); - card_present = hwreg_present((void*) ioaddr+4) - && hwreg_present((void*) ioaddr + DATA_PORT); + card_present = (hwreg_present((void*) ioaddr+4) && + hwreg_present((void*) ioaddr + DATA_PORT)); local_irq_restore(flags); if (!card_present) diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 7d7577b598e..d9fbad38638 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -897,8 +897,8 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) if (next >= N_RX_RING) next = 0; np = mp->rx_cmds + next; - if (next != mp->rx_fill - && (ld_le16(&np->xfer_status) & ACTIVE) != 0) { + if (next != mp->rx_fill && + (ld_le16(&np->xfer_status) & ACTIVE) != 0) { printk(KERN_DEBUG "mace: lost a status word\n"); ++mace_lost_status; } else diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index ae2b5c79c55..21a9c9ab4b3 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -29,6 +29,7 @@ #include <linux/if_link.h> #include <linux/if_macvlan.h> #include <net/rtnetlink.h> +#include <net/xfrm.h> #define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE) @@ -59,6 +60,7 @@ struct macvlan_dev { struct macvlan_port *port; struct net_device *lowerdev; struct macvlan_rx_stats *rx_stats; + enum macvlan_mode mode; }; @@ -116,42 +118,67 @@ static int macvlan_addr_busy(const struct macvlan_port *port, return 0; } +static inline void macvlan_count_rx(const struct macvlan_dev *vlan, + unsigned int len, bool success, + bool multicast) +{ + struct macvlan_rx_stats *rx_stats; + + rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id()); + if (likely(success)) { + rx_stats->rx_packets++;; + rx_stats->rx_bytes += len; + if (multicast) + rx_stats->multicast++; + } else { + rx_stats->rx_errors++; + } +} + +static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev, + const struct ethhdr *eth, bool local) +{ + if (!skb) + return NET_RX_DROP; + + if (local) + return dev_forward_skb(dev, skb); + + skb->dev = dev; + if (!compare_ether_addr_64bits(eth->h_dest, + dev->broadcast)) + skb->pkt_type = PACKET_BROADCAST; + else + skb->pkt_type = PACKET_MULTICAST; + + return netif_rx(skb); +} + static void macvlan_broadcast(struct sk_buff *skb, - const struct macvlan_port *port) + const struct macvlan_port *port, + struct net_device *src, + enum macvlan_mode mode) { const struct ethhdr *eth = eth_hdr(skb); const struct macvlan_dev *vlan; struct hlist_node *n; - struct net_device *dev; struct sk_buff *nskb; unsigned int i; - struct macvlan_rx_stats *rx_stats; + int err; if (skb->protocol == htons(ETH_P_PAUSE)) return; for (i = 0; i < MACVLAN_HASH_SIZE; i++) { hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) { - dev = vlan->dev; - rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id()); - - nskb = skb_clone(skb, GFP_ATOMIC); - if (nskb == NULL) { - rx_stats->rx_errors++; + if (vlan->dev == src || !(vlan->mode & mode)) continue; - } - - rx_stats->rx_bytes += skb->len + ETH_HLEN; - rx_stats->rx_packets++; - rx_stats->multicast++; - nskb->dev = dev; - if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) - nskb->pkt_type = PACKET_BROADCAST; - else - nskb->pkt_type = PACKET_MULTICAST; - - netif_rx(nskb); + nskb = skb_clone(skb, GFP_ATOMIC); + err = macvlan_broadcast_one(nskb, vlan->dev, eth, + mode == MACVLAN_MODE_BRIDGE); + macvlan_count_rx(vlan, skb->len + ETH_HLEN, + err == NET_RX_SUCCESS, 1); } } } @@ -162,15 +189,34 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) const struct ethhdr *eth = eth_hdr(skb); const struct macvlan_port *port; const struct macvlan_dev *vlan; + const struct macvlan_dev *src; struct net_device *dev; - struct macvlan_rx_stats *rx_stats; + unsigned int len; port = rcu_dereference(skb->dev->macvlan_port); if (port == NULL) return skb; if (is_multicast_ether_addr(eth->h_dest)) { - macvlan_broadcast(skb, port); + src = macvlan_hash_lookup(port, eth->h_source); + if (!src) + /* frame comes from an external address */ + macvlan_broadcast(skb, port, NULL, + MACVLAN_MODE_PRIVATE | + MACVLAN_MODE_VEPA | + MACVLAN_MODE_BRIDGE); + else if (src->mode == MACVLAN_MODE_VEPA) + /* flood to everyone except source */ + macvlan_broadcast(skb, port, src->dev, + MACVLAN_MODE_VEPA | + MACVLAN_MODE_BRIDGE); + else if (src->mode == MACVLAN_MODE_BRIDGE) + /* + * flood only to VEPA ports, bridge ports + * already saw the frame on the way out. + */ + macvlan_broadcast(skb, port, src->dev, + MACVLAN_MODE_VEPA); return skb; } @@ -183,15 +229,11 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) kfree_skb(skb); return NULL; } - rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id()); + len = skb->len + ETH_HLEN; skb = skb_share_check(skb, GFP_ATOMIC); - if (skb == NULL) { - rx_stats->rx_errors++; + macvlan_count_rx(vlan, len, skb != NULL, 0); + if (!skb) return NULL; - } - - rx_stats->rx_bytes += skb->len + ETH_HLEN; - rx_stats->rx_packets++; skb->dev = dev; skb->pkt_type = PACKET_HOST; @@ -200,18 +242,46 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) return NULL; } +static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) +{ + const struct macvlan_dev *vlan = netdev_priv(dev); + const struct macvlan_port *port = vlan->port; + const struct macvlan_dev *dest; + + if (vlan->mode == MACVLAN_MODE_BRIDGE) { + const struct ethhdr *eth = (void *)skb->data; + + /* send to other bridge ports directly */ + if (is_multicast_ether_addr(eth->h_dest)) { + macvlan_broadcast(skb, port, dev, MACVLAN_MODE_BRIDGE); + goto xmit_world; + } + + dest = macvlan_hash_lookup(port, eth->h_dest); + if (dest && dest->mode == MACVLAN_MODE_BRIDGE) { + unsigned int length = skb->len + ETH_HLEN; + int ret = dev_forward_skb(dest->dev, skb); + macvlan_count_rx(dest, length, + ret == NET_RX_SUCCESS, 0); + + return NET_XMIT_SUCCESS; + } + } + +xmit_world: + skb->dev = vlan->lowerdev; + return dev_queue_xmit(skb); +} + static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev) { int i = skb_get_queue_mapping(skb); struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - const struct macvlan_dev *vlan = netdev_priv(dev); unsigned int len = skb->len; int ret; - skb->dev = vlan->lowerdev; - ret = dev_queue_xmit(skb); - + ret = macvlan_queue_xmit(skb, dev); if (likely(ret == NET_XMIT_SUCCESS)) { txq->tx_packets++; txq->tx_bytes += len; @@ -376,6 +446,7 @@ static int macvlan_init(struct net_device *dev) dev->state = (dev->state & ~MACVLAN_STATE_MASK) | (lowerdev->state & MACVLAN_STATE_MASK); dev->features = lowerdev->features & MACVLAN_FEATURES; + dev->gso_max_size = lowerdev->gso_max_size; dev->iflink = lowerdev->ifindex; dev->hard_header_len = lowerdev->hard_header_len; @@ -511,25 +582,6 @@ static void macvlan_port_destroy(struct net_device *dev) kfree(port); } -static void macvlan_transfer_operstate(struct net_device *dev) -{ - struct macvlan_dev *vlan = netdev_priv(dev); - const struct net_device *lowerdev = vlan->lowerdev; - - if (lowerdev->operstate == IF_OPER_DORMANT) - netif_dormant_on(dev); - else - netif_dormant_off(dev); - - if (netif_carrier_ok(lowerdev)) { - if (!netif_carrier_ok(dev)) - netif_carrier_on(dev); - } else { - if (netif_carrier_ok(dev)) - netif_carrier_off(dev); - } -} - static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) { if (tb[IFLA_ADDRESS]) { @@ -538,6 +590,17 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) return -EADDRNOTAVAIL; } + + if (data && data[IFLA_MACVLAN_MODE]) { + switch (nla_get_u32(data[IFLA_MACVLAN_MODE])) { + case MACVLAN_MODE_PRIVATE: + case MACVLAN_MODE_VEPA: + case MACVLAN_MODE_BRIDGE: + break; + default: + return -EINVAL; + } + } return 0; } @@ -602,12 +665,16 @@ static int macvlan_newlink(struct net *src_net, struct net_device *dev, vlan->dev = dev; vlan->port = port; + vlan->mode = MACVLAN_MODE_VEPA; + if (data && data[IFLA_MACVLAN_MODE]) + vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + err = register_netdevice(dev); if (err < 0) return err; list_add_tail(&vlan->list, &port->vlans); - macvlan_transfer_operstate(dev); + netif_stacked_transfer_operstate(lowerdev, dev); return 0; } @@ -623,6 +690,36 @@ static void macvlan_dellink(struct net_device *dev, struct list_head *head) macvlan_port_destroy(port->dev); } +static int macvlan_changelink(struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + if (data && data[IFLA_MACVLAN_MODE]) + vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); + return 0; +} + +static size_t macvlan_get_size(const struct net_device *dev) +{ + return nla_total_size(4); +} + +static int macvlan_fill_info(struct sk_buff *skb, + const struct net_device *dev) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + + NLA_PUT_U32(skb, IFLA_MACVLAN_MODE, vlan->mode); + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static const struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX + 1] = { + [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, +}; + static struct rtnl_link_ops macvlan_link_ops __read_mostly = { .kind = "macvlan", .priv_size = sizeof(struct macvlan_dev), @@ -631,6 +728,11 @@ static struct rtnl_link_ops macvlan_link_ops __read_mostly = { .validate = macvlan_validate, .newlink = macvlan_newlink, .dellink = macvlan_dellink, + .maxtype = IFLA_MACVLAN_MAX, + .policy = macvlan_policy, + .changelink = macvlan_changelink, + .get_size = macvlan_get_size, + .fill_info = macvlan_fill_info, }; static int macvlan_device_event(struct notifier_block *unused, @@ -647,11 +749,13 @@ static int macvlan_device_event(struct notifier_block *unused, switch (event) { case NETDEV_CHANGE: list_for_each_entry(vlan, &port->vlans, list) - macvlan_transfer_operstate(vlan->dev); + netif_stacked_transfer_operstate(vlan->lowerdev, + vlan->dev); break; case NETDEV_FEAT_CHANGE: list_for_each_entry(vlan, &port->vlans, list) { vlan->dev->features = dev->features & MACVLAN_FEATURES; + vlan->dev->gso_max_size = dev->gso_max_size; netdev_features_change(vlan->dev); } break; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index b62e61d4ca3..796a493f95a 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -849,7 +849,7 @@ no_csum: return 0; } -static int mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t mv643xx_eth_xmit(struct sk_buff *skb, struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); int queue; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 85e1b6a3ac1..d38921906bb 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -410,8 +410,8 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, * and try to get the completion quickly * (1ms will be enough for those commands) */ for (sleep_total = 0; - sleep_total < 1000 - && response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT); + sleep_total < 1000 && + response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT); sleep_total += 10) { udelay(10); mb(); @@ -419,8 +419,8 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, } else { /* use msleep for most command */ for (sleep_total = 0; - sleep_total < 15 - && response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT); + sleep_total < 15 && + response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT); sleep_total++) msleep(1); } @@ -557,8 +557,8 @@ myri10ge_validate_firmware(struct myri10ge_priv *mgp, sscanf(mgp->fw_version, "%d.%d.%d", &mgp->fw_ver_major, &mgp->fw_ver_minor, &mgp->fw_ver_tiny); - if (!(mgp->fw_ver_major == MXGEFW_VERSION_MAJOR - && mgp->fw_ver_minor == MXGEFW_VERSION_MINOR)) { + if (!(mgp->fw_ver_major == MXGEFW_VERSION_MAJOR && + mgp->fw_ver_minor == MXGEFW_VERSION_MINOR)) { dev_err(dev, "Found firmware version %s\n", mgp->fw_version); dev_err(dev, "Driver needs %d.%d\n", MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); @@ -1412,8 +1412,8 @@ myri10ge_tx_done(struct myri10ge_slice_state *ss, int mcp_index) } /* start the queue if we've stopped it */ - if (netif_tx_queue_stopped(dev_queue) - && tx->req - tx->done < (tx->mask >> 1)) { + if (netif_tx_queue_stopped(dev_queue) && + tx->req - tx->done < (tx->mask >> 1)) { tx->wake_queue++; netif_tx_wake_queue(dev_queue); } diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 9a8d3ab4709..797fe164ce2 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -683,8 +683,8 @@ static ssize_t natsemi_set_dspcfg_workaround(struct device *dev, /* Find out the new setting */ if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1)) new_setting = 1; - else if (!strncmp("off", buf, count - 1) - || !strncmp("0", buf, count - 1)) + else if (!strncmp("off", buf, count - 1) || + !strncmp("0", buf, count - 1)) new_setting = 0; else return count; @@ -757,8 +757,8 @@ static void __devinit natsemi_init_media (struct net_device *dev) np->autoneg = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE; np->advertising= mdio_read(dev, MII_ADVERTISE); - if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL - && netif_msg_probe(np)) { + if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL && + netif_msg_probe(np)) { printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s " "10%s %s duplex.\n", pci_name(np->pci_dev), @@ -1153,8 +1153,8 @@ static void init_phy_fixup(struct net_device *dev) tmp = mdio_read(dev, MII_BMCR); if (np->autoneg == AUTONEG_ENABLE) { /* renegotiate if something changed */ - if ((tmp & BMCR_ANENABLE) == 0 - || np->advertising != mdio_read(dev, MII_ADVERTISE)) + if ((tmp & BMCR_ANENABLE) == 0 || + np->advertising != mdio_read(dev, MII_ADVERTISE)) { /* turn on autonegotiation and force negotiation */ tmp |= (BMCR_ANENABLE | BMCR_ANRESTART); @@ -2164,8 +2164,8 @@ static void netdev_tx_done(struct net_device *dev) dev_kfree_skb_irq(np->tx_skbuff[entry]); np->tx_skbuff[entry] = NULL; } - if (netif_queue_stopped(dev) - && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { + if (netif_queue_stopped(dev) && + np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { /* The ring is no longer full, wake queue. */ netif_wake_queue(dev); } @@ -2343,8 +2343,8 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) /* Omit CRC size. */ /* Check if the packet is long enough to accept * without copying to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + RX_OFFSET)) != NULL) { + if (pkt_len < rx_copybreak && + (skb = dev_alloc_skb(pkt_len + RX_OFFSET)) != NULL) { /* 16 byte align the IP header */ skb_reserve(skb, RX_OFFSET); pci_dma_sync_single_for_cpu(np->pci_dev, @@ -2390,8 +2390,8 @@ static void netdev_error(struct net_device *dev, int intr_status) spin_lock(&np->lock); if (intr_status & LinkChange) { u16 lpa = mdio_read(dev, MII_LPA); - if (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE - && netif_msg_link(np)) { + if (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE && + netif_msg_link(np)) { printk(KERN_INFO "%s: Autonegotiation advertising" " %#04x partner %#04x.\n", dev->name, @@ -2488,8 +2488,8 @@ static void __set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ rx_mode = RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { rx_mode = RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys; } else { diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 645450d93f4..76cd1f3e9fc 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -1202,6 +1202,8 @@ struct netxen_adapter { u32 int_vec_bit; u32 heartbit; + u8 mac_addr[ETH_ALEN]; + struct netxen_adapter_stats stats; struct netxen_recv_context recv_ctx; diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index c86095eb5d9..ddd704ae018 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -257,18 +257,18 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) /* read which mode */ if (adapter->ahw.port_type == NETXEN_NIC_GBE) { /* autonegotiation */ - if (adapter->phy_write - && adapter->phy_write(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, - ecmd->autoneg) != 0) + if (adapter->phy_write && + adapter->phy_write(adapter, + NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, + ecmd->autoneg) != 0) return -EIO; else adapter->link_autoneg = ecmd->autoneg; - if (adapter->phy_read - && adapter->phy_read(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - &status) != 0) + if (adapter->phy_read && + adapter->phy_read(adapter, + NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + &status) != 0) return -EIO; /* speed */ @@ -288,10 +288,10 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) netxen_clear_phy_duplex(status); if (ecmd->duplex == DUPLEX_FULL) netxen_set_phy_duplex(status); - if (adapter->phy_write - && adapter->phy_write(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - *((int *)&status)) != 0) + if (adapter->phy_write && + adapter->phy_write(adapter, + NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + *((int *)&status)) != 0) return -EIO; else { adapter->link_speed = ecmd->speed; @@ -442,10 +442,10 @@ static u32 netxen_nic_test_link(struct net_device *dev) /* read which mode */ if (adapter->ahw.port_type == NETXEN_NIC_GBE) { - if (adapter->phy_read - && adapter->phy_read(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - &status) != 0) + if (adapter->phy_read && + adapter->phy_read(adapter, + NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + &status) != 0) return -EIO; else { val = netxen_get_phy_link(status); diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index a39155d61ba..d138fc22927 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h @@ -545,6 +545,8 @@ enum { #define NETXEN_NIU_TEST_MUX_CTL (NETXEN_CRB_NIU + 0x00094) #define NETXEN_NIU_XG_PAUSE_CTL (NETXEN_CRB_NIU + 0x00098) #define NETXEN_NIU_XG_PAUSE_LEVEL (NETXEN_CRB_NIU + 0x000dc) +#define NETXEN_NIU_FRAME_COUNT_SELECT (NETXEN_CRB_NIU + 0x000ac) +#define NETXEN_NIU_FRAME_COUNT (NETXEN_CRB_NIU + 0x000b0) #define NETXEN_NIU_XG_SEL (NETXEN_CRB_NIU + 0x00128) #define NETXEN_NIU_GB_PAUSE_CTL (NETXEN_CRB_NIU + 0x0030c) diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index b3054c6cc60..2e364fee3cb 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -389,24 +389,51 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) int netxen_p2_nic_set_promisc(struct netxen_adapter *adapter, u32 mode) { - __u32 reg; + u32 mac_cfg; + u32 cnt = 0; + __u32 reg = 0x0200; u32 port = adapter->physical_port; + u16 board_type = adapter->ahw.board_type; if (port > NETXEN_NIU_MAX_XG_PORTS) return -EINVAL; - reg = NXRD32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port)); - if (mode == NETXEN_NIU_PROMISC_MODE) - reg = (reg | 0x2000UL); - else - reg = (reg & ~0x2000UL); + mac_cfg = NXRD32(adapter, NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port)); + mac_cfg &= ~0x4; + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), mac_cfg); - if (mode == NETXEN_NIU_ALLMULTI_MODE) - reg = (reg | 0x1000UL); - else - reg = (reg & ~0x1000UL); + if ((board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) || + (board_type == NETXEN_BRDTYPE_P2_SB31_10G_HMEZ)) + reg = (0x20 << port); + + NXWR32(adapter, NETXEN_NIU_FRAME_COUNT_SELECT, reg); + + mdelay(10); + + while (NXRD32(adapter, NETXEN_NIU_FRAME_COUNT) && ++cnt < 20) + mdelay(10); + + if (cnt < 20) { - NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); + reg = NXRD32(adapter, + NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port)); + + if (mode == NETXEN_NIU_PROMISC_MODE) + reg = (reg | 0x2000UL); + else + reg = (reg & ~0x2000UL); + + if (mode == NETXEN_NIU_ALLMULTI_MODE) + reg = (reg | 0x1000UL); + else + reg = (reg & ~0x1000UL); + + NXWR32(adapter, + NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); + } + + mac_cfg |= 0x4; + NXWR32(adapter, NETXEN_NIU_XGE_CONFIG_0 + (0x10000 * port), mac_cfg); return 0; } @@ -442,7 +469,7 @@ netxen_nic_enable_mcast_filter(struct netxen_adapter *adapter) { u32 val = 0; u16 port = adapter->physical_port; - u8 *addr = adapter->netdev->dev_addr; + u8 *addr = adapter->mac_addr; if (adapter->mc_enabled) return 0; @@ -471,7 +498,7 @@ netxen_nic_disable_mcast_filter(struct netxen_adapter *adapter) { u32 val = 0; u16 port = adapter->physical_port; - u8 *addr = adapter->netdev->dev_addr; + u8 *addr = adapter->mac_addr; if (!adapter->mc_enabled) return 0; @@ -666,7 +693,7 @@ void netxen_p3_nic_set_multi(struct net_device *netdev) list_splice_tail_init(&adapter->mac_list, &del_list); - nx_p3_nic_add_mac(adapter, netdev->dev_addr, &del_list); + nx_p3_nic_add_mac(adapter, adapter->mac_addr, &del_list); nx_p3_nic_add_mac(adapter, bcast_addr, &del_list); if (netdev->flags & IFF_PROMISC) { @@ -1148,24 +1175,46 @@ netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong off) adapter->ahw.crb_win = window; } +static void __iomem * +netxen_nic_map_indirect_address_128M(struct netxen_adapter *adapter, + ulong win_off, void __iomem **mem_ptr) +{ + ulong off = win_off; + void __iomem *addr; + resource_size_t mem_base; + + if (ADDR_IN_WINDOW1(win_off)) + off = NETXEN_CRB_NORMAL(win_off); + + addr = pci_base_offset(adapter, off); + if (addr) + return addr; + + if (adapter->ahw.pci_len0 == 0) + off -= NETXEN_PCI_CRBSPACE; + + mem_base = pci_resource_start(adapter->pdev, 0); + *mem_ptr = ioremap(mem_base + (off & PAGE_MASK), PAGE_SIZE); + if (*mem_ptr) + addr = *mem_ptr + (off & (PAGE_SIZE - 1)); + + return addr; +} + static int netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, ulong off, u32 data) { unsigned long flags; - void __iomem *addr; - - if (ADDR_IN_WINDOW1(off)) - addr = NETXEN_CRB_NORMALIZE(adapter, off); - else - addr = pci_base_offset(adapter, off); + void __iomem *addr, *mem_ptr = NULL; - BUG_ON(!addr); + addr = netxen_nic_map_indirect_address_128M(adapter, off, &mem_ptr); + if (!addr) + return -EIO; - if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ + if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ netxen_nic_io_write_128M(adapter, addr, data); - } else { /* Window 0 */ + } else { /* Window 0 */ write_lock_irqsave(&adapter->ahw.crb_lock, flags); - addr = pci_base_offset(adapter, off); netxen_nic_pci_set_crbwindow_128M(adapter, 0); writel(data, addr); netxen_nic_pci_set_crbwindow_128M(adapter, @@ -1173,6 +1222,9 @@ netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter, ulong off, u32 data) write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); } + if (mem_ptr) + iounmap(mem_ptr); + return 0; } @@ -1180,19 +1232,16 @@ static u32 netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off) { unsigned long flags; - void __iomem *addr; + void __iomem *addr, *mem_ptr = NULL; u32 data; - if (ADDR_IN_WINDOW1(off)) - addr = NETXEN_CRB_NORMALIZE(adapter, off); - else - addr = pci_base_offset(adapter, off); - - BUG_ON(!addr); + addr = netxen_nic_map_indirect_address_128M(adapter, off, &mem_ptr); + if (!addr) + return -EIO; - if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ + if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ data = netxen_nic_io_read_128M(adapter, addr); - } else { /* Window 0 */ + } else { /* Window 0 */ write_lock_irqsave(&adapter->ahw.crb_lock, flags); netxen_nic_pci_set_crbwindow_128M(adapter, 0); data = readl(addr); @@ -1201,6 +1250,9 @@ netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter, ulong off) write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); } + if (mem_ptr) + iounmap(mem_ptr); + return data; } @@ -1884,10 +1936,10 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) return; } - if (adapter->phy_read - && adapter->phy_read(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, - &status) == 0) { + if (adapter->phy_read && + adapter->phy_read(adapter, + NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, + &status) == 0) { if (netxen_get_phy_link(status)) { switch (netxen_get_phy_speed(status)) { case 0: @@ -1914,10 +1966,10 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) adapter->link_duplex = -1; break; } - if (adapter->phy_read - && adapter->phy_read(adapter, - NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, - &autoneg) != 0) + if (adapter->phy_read && + adapter->phy_read(adapter, + NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, + &autoneg) != 0) adapter->link_autoneg = autoneg; } else goto link_down; diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 6ee27a630d8..80a66746051 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -528,6 +528,8 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter) continue; if (off == (ROMUSB_GLB + 0x1c)) /* MS clock */ continue; + if ((off & 0x0ff00000) == NETXEN_CRB_DDR_NET) + continue; if (off == (NETXEN_CRB_PEG_NET_1 + 0x18) && !NX_IS_REVISION_P3P(adapter->ahw.revision_id)) buf[i].data = 0x1020; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index bfbf75c17cf..e5d187fce51 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -445,6 +445,7 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) netdev->dev_addr[i] = *(p + 5 - i); memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len); + memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len); /* set station address */ @@ -467,6 +468,7 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p) netxen_napi_disable(adapter); } + memcpy(adapter->mac_addr, addr->sa_data, netdev->addr_len); memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); adapter->macaddr_set(adapter, addr->sa_data); @@ -817,7 +819,7 @@ netxen_start_firmware(struct netxen_adapter *adapter) if (err < 0) goto err_out; if (err == 0) - goto ready; + goto wait_init; if (first_boot != 0x55555555) { NXWR32(adapter, CRB_CMDPEG_STATE, 0); @@ -860,9 +862,6 @@ netxen_start_firmware(struct netxen_adapter *adapter) | (_NETXEN_NIC_LINUX_SUBVERSION); NXWR32(adapter, CRB_DRIVER_VERSION, val); -ready: - NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_READY); - wait_init: /* Handshake with the card before we register the devices. */ err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); @@ -871,6 +870,8 @@ wait_init: goto err_out; } + NXWR32(adapter, NX_CRB_DEV_STATE, NX_DEV_READY); + nx_update_dma_mask(adapter); netxen_check_options(adapter); @@ -960,7 +961,7 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev) return err; } if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) - adapter->macaddr_set(adapter, netdev->dev_addr); + adapter->macaddr_set(adapter, adapter->mac_addr); adapter->set_multi(netdev); adapter->set_mtu(adapter, netdev->mtu); @@ -1280,7 +1281,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = netxen_start_firmware(adapter); if (err) - goto err_out_iounmap; + goto err_out_decr_ref; /* * See if the firmware gave us a virtual-physical port mapping. @@ -1324,6 +1325,7 @@ err_out_disable_msi: netxen_free_dummy_dma(adapter); +err_out_decr_ref: nx_decr_dev_ref_cnt(adapter); err_out_iounmap: @@ -2187,14 +2189,13 @@ netxen_fwinit_work(struct work_struct *work) netxen_fwinit_work, 2 * FW_POLL_DELAY); return; } - break; case NX_DEV_FAILED: default: + nx_incr_dev_ref_cnt(adapter); break; } - nx_incr_dev_ref_cnt(adapter); clear_bit(__NX_RESETTING, &adapter->state); } @@ -2216,18 +2217,23 @@ netxen_detach_work(struct work_struct *work) status = NXRD32(adapter, NETXEN_PEG_HALT_STATUS1); - ref_cnt = nx_decr_dev_ref_cnt(adapter); - if (status & NX_RCODE_FATAL_ERROR) - return; + goto err_ret; if (adapter->temp == NX_TEMP_PANIC) - return; + goto err_ret; + + ref_cnt = nx_decr_dev_ref_cnt(adapter); delay = (ref_cnt == 0) ? 0 : (2 * FW_POLL_DELAY); adapter->fw_wait_cnt = 0; netxen_schedule_work(adapter, netxen_fwinit_work, delay); + + return; + +err_ret: + clear_bit(__NX_RESETTING, &adapter->state); } static int diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 305f4ba3699..b42f5e522f9 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -477,8 +477,8 @@ static int __init ni52_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < ETH_ALEN; i++) dev->dev_addr[i] = inb(dev->base_addr+i); - if (dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 - || dev->dev_addr[2] != NI52_ADDR2) { + if (dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 || + dev->dev_addr[2] != NI52_ADDR2) { retval = -ENODEV; goto out; } diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 57fd483dbb1..1f6327d4153 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -648,8 +648,8 @@ static void phy_intr(struct net_device *ndev) dprintk("phy_intr: tbisr=%08x, tanar=%08x, tanlpar=%08x\n", tbisr, tanar, tanlpar); - if ( (fullduplex = (tanlpar & TANAR_FULL_DUP) - && (tanar & TANAR_FULL_DUP)) ) { + if ( (fullduplex = (tanlpar & TANAR_FULL_DUP) && + (tanar & TANAR_FULL_DUP)) ) { /* both of us are full duplex */ writel(readl(dev->base + TXCFG) @@ -661,12 +661,12 @@ static void phy_intr(struct net_device *ndev) writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT, dev->base + GPIOR); - } else if(((tanlpar & TANAR_HALF_DUP) - && (tanar & TANAR_HALF_DUP)) - || ((tanlpar & TANAR_FULL_DUP) - && (tanar & TANAR_HALF_DUP)) - || ((tanlpar & TANAR_HALF_DUP) - && (tanar & TANAR_FULL_DUP))) { + } else if (((tanlpar & TANAR_HALF_DUP) && + (tanar & TANAR_HALF_DUP)) || + ((tanlpar & TANAR_FULL_DUP) && + (tanar & TANAR_HALF_DUP)) || + ((tanlpar & TANAR_HALF_DUP) && + (tanar & TANAR_FULL_DUP))) { /* one or both of us are half duplex */ writel((readl(dev->base + TXCFG) @@ -720,16 +720,16 @@ static void phy_intr(struct net_device *ndev) newlinkstate = (cfg & CFG_LNKSTS) ? LINK_UP : LINK_DOWN; - if (newlinkstate & LINK_UP - && dev->linkstate != newlinkstate) { + if (newlinkstate & LINK_UP && + dev->linkstate != newlinkstate) { netif_start_queue(ndev); netif_wake_queue(ndev); printk(KERN_INFO "%s: link now %s mbps, %s duplex and up.\n", ndev->name, speeds[speed], fullduplex ? "full" : "half"); - } else if (newlinkstate & LINK_DOWN - && dev->linkstate != newlinkstate) { + } else if (newlinkstate & LINK_DOWN && + dev->linkstate != newlinkstate) { netif_stop_queue(ndev); printk(KERN_INFO "%s: link now down.\n", ndev->name); } diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 0c44b48f138..480af402aff 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -1225,8 +1225,8 @@ static void netdrv_timer (unsigned long data) mii_lpa = mdio_read (dev, tp->phys[0], MII_LPA); if (!tp->duplex_lock && mii_lpa != 0xffff) { - int duplex = (mii_lpa & LPA_100FULL) - || (mii_lpa & 0x01C0) == 0x0040; + int duplex = ((mii_lpa & LPA_100FULL) || + (mii_lpa & 0x01C0) == 0x0040); if (tp->full_duplex != duplex) { tp->full_duplex = duplex; printk (KERN_INFO @@ -1612,8 +1612,8 @@ static void netdrv_weird_interrupt (struct net_device *dev, (tp->drv_flags & HAS_LNK_CHNG)) { /* Really link-change on new chips. */ int lpar = NETDRV_R16 (NWayLPAR); - int duplex = (lpar & 0x0100) || (lpar & 0x01C0) == 0x0040 - || tp->duplex_lock; + int duplex = ((lpar & 0x0100) || (lpar & 0x01C0) == 0x0040 || + tp->duplex_lock); if (tp->full_duplex != duplex) { tp->full_duplex = duplex; NETDRV_W8 (Cfg9346, Cfg9346_Unlock); @@ -1820,8 +1820,8 @@ static void netdrv_set_rx_mode (struct net_device *dev) AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 3131a59a8d3..ca711f46814 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -1232,8 +1232,8 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id) ei_local->irqlock = 1; /* !!Assumption!! -- we stay in page 0. Don't break this. */ - while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 - && ++nr_serviced < MAX_SERVICE) + while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 && + ++nr_serviced < MAX_SERVICE) { if (!netif_running(dev) || (interrupts == 0xff)) { if (ei_debug > 1) diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 57e09616330..a6961215cd5 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -371,9 +371,9 @@ static int fmvj18x_config(struct pcmcia_device *link) switch (link->manf_id) { case MANFID_TDK: cardtype = TDK; - if (link->card_id == PRODID_TDK_GN3410 - || link->card_id == PRODID_TDK_NP9610 - || link->card_id == PRODID_TDK_MN3200) { + if (link->card_id == PRODID_TDK_GN3410 || + link->card_id == PRODID_TDK_NP9610 || + link->card_id == PRODID_TDK_MN3200) { /* MultiFunction Card */ link->conf.ConfigBase = 0x800; link->conf.ConfigIndex = 0x47; @@ -590,11 +590,11 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id) */ for (i = 0; i < 0x200; i++) { if (readb(base+i*2) == 0x22) { - if (readb(base+(i-1)*2) == 0xff - && readb(base+(i+5)*2) == 0x04 - && readb(base+(i+6)*2) == 0x06 - && readb(base+(i+13)*2) == 0xff) - break; + if (readb(base+(i-1)*2) == 0xff && + readb(base+(i+5)*2) == 0x04 && + readb(base+(i+6)*2) == 0x06 && + readb(base+(i+13)*2) == 0xff) + break; } } @@ -1219,8 +1219,8 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { memset(mc_filter, 0xff, sizeof(mc_filter)); outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ - } else if (dev->mc_count > MC_FILTERBREAK - || (dev->flags & IFF_ALLMULTI)) { + } else if (dev->mc_count > MC_FILTERBREAK || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); outb(2, ioaddr + RX_MODE); /* Use normal mode. */ diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 469684474b7..347eaee855c 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -601,8 +601,8 @@ static int pcnet_config(struct pcmcia_device *link) dev->if_port = 0; } - if ((link->conf.ConfigBase == 0x03c0) - && (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) { + if ((link->conf.ConfigBase == 0x03c0) && + (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) { printk(KERN_INFO "pcnet_cs: this is an AX88190 card!\n"); printk(KERN_INFO "pcnet_cs: use axnet_cs instead.\n"); goto failed; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 7bde2cd34c7..117b083a10c 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -526,10 +526,10 @@ static int mhz_mfc_config(struct pcmcia_device *link) mem.CardOffset = link->conf.ConfigBase; i = pcmcia_map_mem_page(link->win, &mem); - if ((i == 0) - && (smc->manfid == MANFID_MEGAHERTZ) - && (smc->cardid == PRODID_MEGAHERTZ_EM3288)) - mhz_3288_power(link); + if ((i == 0) && + (smc->manfid == MANFID_MEGAHERTZ) && + (smc->cardid == PRODID_MEGAHERTZ_EM3288)) + mhz_3288_power(link); free_cfg_mem: kfree(cfg_mem); diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index cf842310253..187da21f720 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -421,9 +421,9 @@ PrintRegisters(struct net_device *dev) printk("\n"); } for (page=0x40 ; page <= 0x5f; page++) { - if (page == 0x43 || (page >= 0x46 && page <= 0x4f) - || (page >= 0x51 && page <=0x5e)) - continue; + if (page == 0x43 || (page >= 0x46 && page <= 0x4f) || + (page >= 0x51 && page <=0x5e)) + continue; printk(KDBG_XIRC "Register page %2x: ", page); SelectPage(page); for (i = 8; i < 16; i++) @@ -834,9 +834,9 @@ xirc2ps_config(struct pcmcia_device * link) /* Once I saw two CISTPL_FUNCE_LAN_NODE_ID entries: * the first one with a length of zero the second correct - * so I skip all entries with length 0 */ - if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID - && ((cistpl_lan_node_id_t *)parse.funce.data)->nb) - break; + if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID && + ((cistpl_lan_node_id_t *)parse.funce.data)->nb) + break; } if (err) { /* not found: try to get the node-id from tuple 0x89 */ tuple.DesiredTuple = 0x89; /* data layout looks like tuple 0x22 */ @@ -852,8 +852,8 @@ xirc2ps_config(struct pcmcia_device * link) tuple.DesiredTuple = CISTPL_FUNCE; for (err = first_tuple(link, &tuple, &parse); !err; err = next_tuple(link, &tuple, &parse)) { - if (parse.funce.type == 0x02 && parse.funce.data[0] == 1 - && parse.funce.data[1] == 6 && tuple.TupleDataLen == 13) { + if (parse.funce.type == 0x02 && parse.funce.data[0] == 1 && + parse.funce.data[1] == 6 && tuple.TupleDataLen == 13) { buf[1] = 4; memcpy(&parse, buf+1, 8); break; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 076f23a1051..dcc67a35e8f 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1515,8 +1515,8 @@ static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist) if (request_region (ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_vlbus")) { /* check if there is really a pcnet chip on that ioaddr */ - if ((inb(ioaddr + 14) == 0x57) - && (inb(ioaddr + 15) == 0x57)) { + if ((inb(ioaddr + 14) == 0x57) && + (inb(ioaddr + 15) == 0x57)) { pcnet32_probe1(ioaddr, 0, NULL); } else { release_region(ioaddr, PCNET32_TOTAL_SIZE); @@ -1610,8 +1610,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) a = &pcnet32_wio; } else { pcnet32_dwio_reset(ioaddr); - if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 - && pcnet32_dwio_check(ioaddr)) { + if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && + pcnet32_dwio_check(ioaddr)) { a = &pcnet32_dwio; } else { if (pcnet32_debug & NETIF_MSG_PROBE) @@ -1750,8 +1750,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) for (i = 0; i < 6; i++) promaddr[i] = inb(ioaddr + i); - if (memcmp(promaddr, dev->dev_addr, 6) - || !is_valid_ether_addr(dev->dev_addr)) { + if (memcmp(promaddr, dev->dev_addr, 6) || + !is_valid_ether_addr(dev->dev_addr)) { if (is_valid_ether_addr(promaddr)) { if (pcnet32_debug & NETIF_MSG_PROBE) { printk(" warning: CSR address invalid,\n"); @@ -1840,8 +1840,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) lp->mii = mii; lp->chip_version = chip_version; lp->msg_enable = pcnet32_debug; - if ((cards_found >= MAX_UNITS) - || (options[cards_found] >= sizeof(options_mapping))) + if ((cards_found >= MAX_UNITS) || + (options[cards_found] >= sizeof(options_mapping))) lp->options = PCNET32_PORT_ASEL; else lp->options = options_mapping[options[cards_found]]; @@ -1866,8 +1866,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) goto err_free_ring; } /* detect special T1/E1 WAN card by checking for MAC address */ - if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 - && dev->dev_addr[2] == 0x75) + if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && + dev->dev_addr[2] == 0x75) lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; lp->init_block->mode = cpu_to_le16(0x0003); /* Disable Rx and Tx. */ diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 6b71b003406..b0e9f9c5172 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -254,12 +254,12 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) return -EINVAL; - if (cmd->autoneg == AUTONEG_DISABLE - && ((cmd->speed != SPEED_1000 - && cmd->speed != SPEED_100 - && cmd->speed != SPEED_10) - || (cmd->duplex != DUPLEX_HALF - && cmd->duplex != DUPLEX_FULL))) + if (cmd->autoneg == AUTONEG_DISABLE && + ((cmd->speed != SPEED_1000 && + cmd->speed != SPEED_100 && + cmd->speed != SPEED_10) || + (cmd->duplex != DUPLEX_HALF && + cmd->duplex != DUPLEX_FULL))) return -EINVAL; phydev->autoneg = cmd->autoneg; @@ -353,9 +353,9 @@ int phy_mii_ioctl(struct phy_device *phydev, phy_write(phydev, mii_data->reg_num, val); - if (mii_data->reg_num == MII_BMCR - && val & BMCR_RESET - && phydev->drv->config_init) { + if (mii_data->reg_num == MII_BMCR && + val & BMCR_RESET && + phydev->drv->config_init) { phy_scan_fixups(phydev); phydev->drv->config_init(phydev); } diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 00487f569cf..3327e9fc7b5 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -372,8 +372,8 @@ plip_bh(struct work_struct *work) nl->is_deferred = 0; f = connection_state_table[nl->connection]; - if ((r = (*f)(nl->dev, nl, snd, rcv)) != OK - && (r = plip_bh_timeout_error(nl->dev, nl, snd, rcv, r)) != OK) { + if ((r = (*f)(nl->dev, nl, snd, rcv)) != OK && + (r = plip_bh_timeout_error(nl->dev, nl, snd, rcv, r)) != OK) { nl->is_deferred = 1; schedule_delayed_work(&nl->deferred, 1); } @@ -416,9 +416,8 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, if (error != ERROR) { /* Timeout */ nl->timeout_count++; - if ((error == HS_TIMEOUT - && nl->timeout_count <= 10) - || nl->timeout_count <= 3) { + if ((error == HS_TIMEOUT && nl->timeout_count <= 10) || + nl->timeout_count <= 3) { spin_unlock_irq(&nl->lock); /* Try again later */ return TIMEOUT; @@ -624,8 +623,8 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, if (plip_receive(nibble_timeout, dev, &rcv->nibble, &rcv->length.b.msb)) return TIMEOUT; - if (rcv->length.h > dev->mtu + dev->hard_header_len - || rcv->length.h < 8) { + if (rcv->length.h > dev->mtu + dev->hard_header_len || + rcv->length.h < 8) { printk(KERN_WARNING "%s: bogus packet size %d.\n", dev->name, rcv->length.h); return ERROR; } diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index c311fa6597f..6a375ea4947 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -558,8 +558,8 @@ ppp_async_encode(struct asyncppp *ap) * Start of a new packet - insert the leading FLAG * character if necessary. */ - if (islcp || flag_time == 0 - || time_after_eq(jiffies, ap->last_xmit + flag_time)) + if (islcp || flag_time == 0 || + time_after_eq(jiffies, ap->last_xmit + flag_time)) *buf++ = PPP_FLAG; ap->last_xmit = jiffies; fcs = PPP_INITFCS; @@ -696,8 +696,8 @@ ppp_async_push(struct asyncppp *ap) */ clear_bit(XMIT_BUSY, &ap->xmit_flags); /* any more work to do? if not, exit the loop */ - if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) - || (!tty_stuffed && ap->tpkt))) + if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) || + (!tty_stuffed && ap->tpkt))) break; /* more work to do, see if we can do it now */ if (test_and_set_bit(XMIT_BUSY, &ap->xmit_flags)) @@ -754,8 +754,8 @@ scan_ordinary(struct asyncppp *ap, const unsigned char *buf, int count) for (i = 0; i < count; ++i) { c = buf[i]; - if (c == PPP_ESCAPE || c == PPP_FLAG - || (c < 0x20 && (ap->raccm & (1 << c)) != 0)) + if (c == PPP_ESCAPE || c == PPP_FLAG || + (c < 0x20 && (ap->raccm & (1 << c)) != 0)) break; } return i; diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c index 034c1c650bc..695bc83e0cf 100644 --- a/drivers/net/ppp_deflate.c +++ b/drivers/net/ppp_deflate.c @@ -111,11 +111,11 @@ static void *z_comp_alloc(unsigned char *options, int opt_len) struct ppp_deflate_state *state; int w_size; - if (opt_len != CILEN_DEFLATE - || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) - || options[1] != CILEN_DEFLATE - || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL - || options[3] != DEFLATE_CHK_SEQUENCE) + if (opt_len != CILEN_DEFLATE || + (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || + options[1] != CILEN_DEFLATE || + DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || + options[3] != DEFLATE_CHK_SEQUENCE) return NULL; w_size = DEFLATE_SIZE(options[2]); if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) @@ -163,12 +163,12 @@ static int z_comp_init(void *arg, unsigned char *options, int opt_len, { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - if (opt_len < CILEN_DEFLATE - || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) - || options[1] != CILEN_DEFLATE - || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL - || DEFLATE_SIZE(options[2]) != state->w_size - || options[3] != DEFLATE_CHK_SEQUENCE) + if (opt_len < CILEN_DEFLATE || + (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || + options[1] != CILEN_DEFLATE || + DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || + DEFLATE_SIZE(options[2]) != state->w_size || + options[3] != DEFLATE_CHK_SEQUENCE) return 0; state->seqno = 0; @@ -330,11 +330,11 @@ static void *z_decomp_alloc(unsigned char *options, int opt_len) struct ppp_deflate_state *state; int w_size; - if (opt_len != CILEN_DEFLATE - || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) - || options[1] != CILEN_DEFLATE - || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL - || options[3] != DEFLATE_CHK_SEQUENCE) + if (opt_len != CILEN_DEFLATE || + (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || + options[1] != CILEN_DEFLATE || + DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || + options[3] != DEFLATE_CHK_SEQUENCE) return NULL; w_size = DEFLATE_SIZE(options[2]); if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE) @@ -381,12 +381,12 @@ static int z_decomp_init(void *arg, unsigned char *options, int opt_len, { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; - if (opt_len < CILEN_DEFLATE - || (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) - || options[1] != CILEN_DEFLATE - || DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL - || DEFLATE_SIZE(options[2]) != state->w_size - || options[3] != DEFLATE_CHK_SEQUENCE) + if (opt_len < CILEN_DEFLATE || + (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) || + options[1] != CILEN_DEFLATE || + DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL || + DEFLATE_SIZE(options[2]) != state->w_size || + options[3] != DEFLATE_CHK_SEQUENCE) return 0; state->seqno = 0; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 0a56a778af0..2282e729edb 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -425,8 +425,8 @@ static ssize_t ppp_read(struct file *file, char __user *buf, * network traffic (demand mode). */ struct ppp *ppp = PF_TO_PPP(pf); - if (ppp->n_channels == 0 - && (ppp->flags & SC_LOOP_TRAFFIC) == 0) + if (ppp->n_channels == 0 && + (ppp->flags & SC_LOOP_TRAFFIC) == 0) break; } ret = -EAGAIN; @@ -511,8 +511,8 @@ static unsigned int ppp_poll(struct file *file, poll_table *wait) else if (pf->kind == INTERFACE) { /* see comment in ppp_read */ struct ppp *ppp = PF_TO_PPP(pf); - if (ppp->n_channels == 0 - && (ppp->flags & SC_LOOP_TRAFFIC) == 0) + if (ppp->n_channels == 0 && + (ppp->flags & SC_LOOP_TRAFFIC) == 0) mask |= POLLIN | POLLRDNORM; } @@ -864,12 +864,7 @@ static const struct file_operations ppp_device_fops = { static __net_init int ppp_init_net(struct net *net) { - struct ppp_net *pn; - int err; - - pn = kzalloc(sizeof(*pn), GFP_KERNEL); - if (!pn) - return -ENOMEM; + struct ppp_net *pn = net_generic(net, ppp_net_id); idr_init(&pn->units_idr); mutex_init(&pn->all_ppp_mutex); @@ -879,32 +874,21 @@ static __net_init int ppp_init_net(struct net *net) spin_lock_init(&pn->all_channels_lock); - err = net_assign_generic(net, ppp_net_id, pn); - if (err) { - kfree(pn); - return err; - } - return 0; } static __net_exit void ppp_exit_net(struct net *net) { - struct ppp_net *pn; + struct ppp_net *pn = net_generic(net, ppp_net_id); - pn = net_generic(net, ppp_net_id); idr_destroy(&pn->units_idr); - /* - * if someone has cached our net then - * further net_generic call will return NULL - */ - net_assign_generic(net, ppp_net_id, NULL); - kfree(pn); } static struct pernet_operations ppp_net_ops = { .init = ppp_init_net, .exit = ppp_exit_net, + .id = &ppp_net_id, + .size = sizeof(struct ppp_net), }; #define PPP_MAJOR 108 @@ -917,7 +901,7 @@ static int __init ppp_init(void) printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n"); - err = register_pernet_gen_device(&ppp_net_id, &ppp_net_ops); + err = register_pernet_device(&ppp_net_ops); if (err) { printk(KERN_ERR "failed to register PPP pernet device (%d)\n", err); goto out; @@ -943,7 +927,7 @@ static int __init ppp_init(void) out_chrdev: unregister_chrdev(PPP_MAJOR, "ppp"); out_net: - unregister_pernet_gen_device(ppp_net_id, &ppp_net_ops); + unregister_pernet_device(&ppp_net_ops); out: return err; } @@ -1073,8 +1057,8 @@ ppp_xmit_process(struct ppp *ppp) ppp_xmit_lock(ppp); if (!ppp->closing) { ppp_push(ppp); - while (!ppp->xmit_pending - && (skb = skb_dequeue(&ppp->file.xq))) + while (!ppp->xmit_pending && + (skb = skb_dequeue(&ppp->file.xq))) ppp_send_frame(ppp, skb); /* If there's no work left to do, tell the core net code that we can accept some more. */ @@ -1153,18 +1137,18 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) /* the filter instructions are constructed assuming a four-byte PPP header on each packet */ *skb_push(skb, 2) = 1; - if (ppp->pass_filter - && sk_run_filter(skb, ppp->pass_filter, - ppp->pass_len) == 0) { + if (ppp->pass_filter && + sk_run_filter(skb, ppp->pass_filter, + ppp->pass_len) == 0) { if (ppp->debug & 1) printk(KERN_DEBUG "PPP: outbound frame not passed\n"); kfree_skb(skb); return; } /* if this packet passes the active filter, record the time */ - if (!(ppp->active_filter - && sk_run_filter(skb, ppp->active_filter, - ppp->active_len) == 0)) + if (!(ppp->active_filter && + sk_run_filter(skb, ppp->active_filter, + ppp->active_len) == 0)) ppp->last_xmit = jiffies; skb_pull(skb, 2); #else @@ -1218,8 +1202,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb) } /* try to do packet compression */ - if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state - && proto != PPP_LCP && proto != PPP_CCP) { + if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state && + proto != PPP_LCP && proto != PPP_CCP) { if (!(ppp->flags & SC_CCP_UP) && (ppp->flags & SC_MUST_COMP)) { if (net_ratelimit()) printk(KERN_ERR "ppp: compression required but down - pkt dropped.\n"); @@ -1593,8 +1577,8 @@ ppp_input(struct ppp_channel *chan, struct sk_buff *skb) /* put it on the channel queue */ skb_queue_tail(&pch->file.rq, skb); /* drop old frames if queue too long */ - while (pch->file.rq.qlen > PPP_MAX_RQLEN - && (skb = skb_dequeue(&pch->file.rq))) + while (pch->file.rq.qlen > PPP_MAX_RQLEN && + (skb = skb_dequeue(&pch->file.rq))) kfree_skb(skb); wake_up_interruptible(&pch->file.rwait); } else { @@ -1670,8 +1654,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) * Note that some decompressors need to see uncompressed frames * that come in as well as compressed frames. */ - if (ppp->rc_state && (ppp->rstate & SC_DECOMP_RUN) - && (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0) + if (ppp->rc_state && (ppp->rstate & SC_DECOMP_RUN) && + (ppp->rstate & (SC_DC_FERROR | SC_DC_ERROR)) == 0) skb = ppp_decompress_frame(ppp, skb); if (ppp->flags & SC_MUST_COMP && ppp->rstate & SC_DC_FERROR) @@ -1742,8 +1726,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) /* control or unknown frame - pass it to pppd */ skb_queue_tail(&ppp->file.rq, skb); /* limit queue length by dropping old frames */ - while (ppp->file.rq.qlen > PPP_MAX_RQLEN - && (skb = skb_dequeue(&ppp->file.rq))) + while (ppp->file.rq.qlen > PPP_MAX_RQLEN && + (skb = skb_dequeue(&ppp->file.rq))) kfree_skb(skb); /* wake up any process polling or blocking on read */ wake_up_interruptible(&ppp->file.rwait); @@ -1761,26 +1745,26 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) goto err; *skb_push(skb, 2) = 0; - if (ppp->pass_filter - && sk_run_filter(skb, ppp->pass_filter, - ppp->pass_len) == 0) { + if (ppp->pass_filter && + sk_run_filter(skb, ppp->pass_filter, + ppp->pass_len) == 0) { if (ppp->debug & 1) printk(KERN_DEBUG "PPP: inbound frame " "not passed\n"); kfree_skb(skb); return; } - if (!(ppp->active_filter - && sk_run_filter(skb, ppp->active_filter, - ppp->active_len) == 0)) + if (!(ppp->active_filter && + sk_run_filter(skb, ppp->active_filter, + ppp->active_len) == 0)) ppp->last_recv = jiffies; __skb_pull(skb, 2); } else #endif /* CONFIG_PPP_FILTER */ ppp->last_recv = jiffies; - if ((ppp->dev->flags & IFF_UP) == 0 - || ppp->npmode[npi] != NPMODE_PASS) { + if ((ppp->dev->flags & IFF_UP) == 0 || + ppp->npmode[npi] != NPMODE_PASS) { kfree_skb(skb); } else { /* chop off protocol */ @@ -2244,13 +2228,13 @@ ppp_set_compress(struct ppp *ppp, unsigned long arg) unsigned char ccp_option[CCP_MAX_OPTION_LENGTH]; err = -EFAULT; - if (copy_from_user(&data, (void __user *) arg, sizeof(data)) - || (data.length <= CCP_MAX_OPTION_LENGTH - && copy_from_user(ccp_option, (void __user *) data.ptr, data.length))) + if (copy_from_user(&data, (void __user *) arg, sizeof(data)) || + (data.length <= CCP_MAX_OPTION_LENGTH && + copy_from_user(ccp_option, (void __user *) data.ptr, data.length))) goto out; err = -EINVAL; - if (data.length > CCP_MAX_OPTION_LENGTH - || ccp_option[1] < 2 || ccp_option[1] > data.length) + if (data.length > CCP_MAX_OPTION_LENGTH || + ccp_option[1] < 2 || ccp_option[1] > data.length) goto out; cp = try_then_request_module( @@ -2835,7 +2819,7 @@ static void __exit ppp_cleanup(void) unregister_chrdev(PPP_MAJOR, "ppp"); device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); class_destroy(ppp_class); - unregister_pernet_gen_device(ppp_net_id, &ppp_net_ops); + unregister_pernet_device(&ppp_net_ops); } /* diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c index 88f03c9e940..6d1a1b80cc3 100644 --- a/drivers/net/ppp_mppe.c +++ b/drivers/net/ppp_mppe.c @@ -195,8 +195,8 @@ static void *mppe_alloc(unsigned char *options, int optlen) struct ppp_mppe_state *state; unsigned int digestsize; - if (optlen != CILEN_MPPE + sizeof(state->master_key) - || options[0] != CI_MPPE || options[1] != CILEN_MPPE) + if (optlen != CILEN_MPPE + sizeof(state->master_key) || + options[0] != CI_MPPE || options[1] != CILEN_MPPE) goto out; state = kzalloc(sizeof(*state), GFP_KERNEL); @@ -276,8 +276,8 @@ mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug, struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg; unsigned char mppe_opts; - if (optlen != CILEN_MPPE - || options[0] != CI_MPPE || options[1] != CILEN_MPPE) + if (optlen != CILEN_MPPE || + options[0] != CI_MPPE || options[1] != CILEN_MPPE) return 0; MPPE_CI_TO_OPTS(&options[2], mppe_opts); diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index c908b08dc98..3a13cecae3e 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -662,8 +662,8 @@ ppp_sync_push(struct syncppp *ap) } /* haven't made any progress */ spin_unlock_bh(&ap->xmit_lock); - if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) - || (!tty_stuffed && ap->tpkt))) + if (!(test_bit(XMIT_WAKEUP, &ap->xmit_flags) || + (!tty_stuffed && ap->tpkt))) break; if (!spin_trylock_bh(&ap->xmit_lock)) break; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index a1dcba255b0..cdd11ba100e 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -323,8 +323,8 @@ static void pppoe_flush_dev(struct net_device *dev) write_unlock_bh(&pn->hash_lock); lock_sock(sk); - if (po->pppoe_dev == dev - && sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { + if (po->pppoe_dev == dev && + sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { pppox_unbind_sock(sk); sk->sk_state = PPPOX_ZOMBIE; sk->sk_state_change(sk); @@ -1139,59 +1139,37 @@ static struct pppox_proto pppoe_proto = { static __net_init int pppoe_init_net(struct net *net) { - struct pppoe_net *pn; + struct pppoe_net *pn = pppoe_pernet(net); struct proc_dir_entry *pde; - int err; - - pn = kzalloc(sizeof(*pn), GFP_KERNEL); - if (!pn) - return -ENOMEM; rwlock_init(&pn->hash_lock); - err = net_assign_generic(net, pppoe_net_id, pn); - if (err) - goto out; - pde = proc_net_fops_create(net, "pppoe", S_IRUGO, &pppoe_seq_fops); #ifdef CONFIG_PROC_FS - if (!pde) { - err = -ENOMEM; - goto out; - } + if (!pde) + return -ENOMEM; #endif return 0; - -out: - kfree(pn); - return err; } static __net_exit void pppoe_exit_net(struct net *net) { - struct pppoe_net *pn; - proc_net_remove(net, "pppoe"); - pn = net_generic(net, pppoe_net_id); - /* - * if someone has cached our net then - * further net_generic call will return NULL - */ - net_assign_generic(net, pppoe_net_id, NULL); - kfree(pn); } static struct pernet_operations pppoe_net_ops = { .init = pppoe_init_net, .exit = pppoe_exit_net, + .id = &pppoe_net_id, + .size = sizeof(struct pppoe_net), }; static int __init pppoe_init(void) { int err; - err = register_pernet_gen_device(&pppoe_net_id, &pppoe_net_ops); + err = register_pernet_device(&pppoe_net_ops); if (err) goto out; @@ -1212,7 +1190,7 @@ static int __init pppoe_init(void) out_unregister_pppoe_proto: proto_unregister(&pppoe_sk_proto); out_unregister_net_ops: - unregister_pernet_gen_device(pppoe_net_id, &pppoe_net_ops); + unregister_pernet_device(&pppoe_net_ops); out: return err; } @@ -1224,7 +1202,7 @@ static void __exit pppoe_exit(void) dev_remove_pack(&pppoes_ptype); unregister_pppox_proto(PX_PROTO_OE); proto_unregister(&pppoe_sk_proto); - unregister_pernet_gen_device(pppoe_net_id, &pppoe_net_ops); + unregister_pernet_device(&pppoe_net_ops); } module_init(pppoe_init); diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index c58b50f8ba3..9fbb2eba9a0 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -2605,53 +2605,31 @@ static struct pppox_proto pppol2tp_proto = { static __net_init int pppol2tp_init_net(struct net *net) { - struct pppol2tp_net *pn; + struct pppol2tp_net *pn = pppol2tp_pernet(net); struct proc_dir_entry *pde; - int err; - - pn = kzalloc(sizeof(*pn), GFP_KERNEL); - if (!pn) - return -ENOMEM; INIT_LIST_HEAD(&pn->pppol2tp_tunnel_list); rwlock_init(&pn->pppol2tp_tunnel_list_lock); - err = net_assign_generic(net, pppol2tp_net_id, pn); - if (err) - goto out; - pde = proc_net_fops_create(net, "pppol2tp", S_IRUGO, &pppol2tp_proc_fops); #ifdef CONFIG_PROC_FS - if (!pde) { - err = -ENOMEM; - goto out; - } + if (!pde) + return -ENOMEM; #endif return 0; - -out: - kfree(pn); - return err; } static __net_exit void pppol2tp_exit_net(struct net *net) { - struct pppoe_net *pn; - proc_net_remove(net, "pppol2tp"); - pn = net_generic(net, pppol2tp_net_id); - /* - * if someone has cached our net then - * further net_generic call will return NULL - */ - net_assign_generic(net, pppol2tp_net_id, NULL); - kfree(pn); } static struct pernet_operations pppol2tp_net_ops = { .init = pppol2tp_init_net, .exit = pppol2tp_exit_net, + .id = &pppol2tp_net_id, + .size = sizeof(struct pppol2tp_net), }; static int __init pppol2tp_init(void) @@ -2665,7 +2643,7 @@ static int __init pppol2tp_init(void) if (err) goto out_unregister_pppol2tp_proto; - err = register_pernet_gen_device(&pppol2tp_net_id, &pppol2tp_net_ops); + err = register_pernet_device(&pppol2tp_net_ops); if (err) goto out_unregister_pppox_proto; @@ -2684,7 +2662,7 @@ out_unregister_pppol2tp_proto: static void __exit pppol2tp_exit(void) { unregister_pppox_proto(PX_PROTO_OL2TP); - unregister_pernet_gen_device(pppol2tp_net_id, &pppol2tp_net_ops); + unregister_pernet_device(&pppol2tp_net_ops); proto_unregister(&pppol2tp_sk_proto); } diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index b211613e9db..89c4948300a 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -95,11 +95,11 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card, lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_GET_ETH_PORT_STATUS, - GELIC_LV1_VLAN_TX_ETHERNET, 0, 0, + GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0, &card->ether_port_status, &v2); if (inform) { - ether_netdev = card->netdev[GELIC_PORT_ETHERNET]; + ether_netdev = card->netdev[GELIC_PORT_ETHERNET_0]; if (card->ether_port_status & GELIC_LV1_ETHER_LINK_UP) netif_carrier_on(ether_netdev); else @@ -107,6 +107,24 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card, } } +static int gelic_card_set_link_mode(struct gelic_card *card, int mode) +{ + int status; + u64 v1, v2; + + status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_SET_NEGOTIATION_MODE, + GELIC_LV1_PHY_ETHERNET_0, mode, 0, &v1, &v2); + if (status) { + pr_info("%s: failed setting negotiation mode %d\n", __func__, + status); + return -EBUSY; + } + + card->link_mode = mode; + return 0; +} + void gelic_card_up(struct gelic_card *card) { pr_debug("%s: called\n", __func__); @@ -451,14 +469,14 @@ static void gelic_descr_release_tx(struct gelic_card *card, static void gelic_card_stop_queues(struct gelic_card *card) { - netif_stop_queue(card->netdev[GELIC_PORT_ETHERNET]); + netif_stop_queue(card->netdev[GELIC_PORT_ETHERNET_0]); if (card->netdev[GELIC_PORT_WIRELESS]) netif_stop_queue(card->netdev[GELIC_PORT_WIRELESS]); } static void gelic_card_wake_queues(struct gelic_card *card) { - netif_wake_queue(card->netdev[GELIC_PORT_ETHERNET]); + netif_wake_queue(card->netdev[GELIC_PORT_ETHERNET_0]); if (card->netdev[GELIC_PORT_WIRELESS]) netif_wake_queue(card->netdev[GELIC_PORT_WIRELESS]); @@ -999,7 +1017,7 @@ static int gelic_card_decode_one_descr(struct gelic_card *card) goto refill; } } else - netdev = card->netdev[GELIC_PORT_ETHERNET]; + netdev = card->netdev[GELIC_PORT_ETHERNET_0]; if ((status == GELIC_DESCR_DMA_RESPONSE_ERROR) || (status == GELIC_DESCR_DMA_PROTECTION_ERROR) || @@ -1244,14 +1262,58 @@ static int gelic_ether_get_settings(struct net_device *netdev, cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; + SUPPORTED_1000baseT_Full; cmd->advertising = cmd->supported; - cmd->autoneg = AUTONEG_ENABLE; /* always enabled */ + if (card->link_mode & GELIC_LV1_ETHER_AUTO_NEG) { + cmd->autoneg = AUTONEG_ENABLE; + } else { + cmd->autoneg = AUTONEG_DISABLE; + cmd->advertising &= ~ADVERTISED_Autoneg; + } cmd->port = PORT_TP; return 0; } +static int gelic_ether_set_settings(struct net_device *netdev, + struct ethtool_cmd *cmd) +{ + struct gelic_card *card = netdev_card(netdev); + u64 mode; + int ret; + + if (cmd->autoneg == AUTONEG_ENABLE) { + mode = GELIC_LV1_ETHER_AUTO_NEG; + } else { + switch (cmd->speed) { + case SPEED_10: + mode = GELIC_LV1_ETHER_SPEED_10; + break; + case SPEED_100: + mode = GELIC_LV1_ETHER_SPEED_100; + break; + case SPEED_1000: + mode = GELIC_LV1_ETHER_SPEED_1000; + break; + default: + return -EINVAL; + } + if (cmd->duplex == DUPLEX_FULL) + mode |= GELIC_LV1_ETHER_FULL_DUPLEX; + else if (cmd->speed == SPEED_1000) { + pr_info("1000 half duplex is not supported.\n"); + return -EINVAL; + } + } + + ret = gelic_card_set_link_mode(card, mode); + + if (ret) + return ret; + + return 0; +} + u32 gelic_net_get_rx_csum(struct net_device *netdev) { struct gelic_card *card = netdev_card(netdev); @@ -1349,6 +1411,7 @@ done: static const struct ethtool_ops gelic_ether_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, .get_settings = gelic_ether_get_settings, + .set_settings = gelic_ether_set_settings, .get_link = ethtool_op_get_link, .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, @@ -1369,7 +1432,7 @@ static void gelic_net_tx_timeout_task(struct work_struct *work) { struct gelic_card *card = container_of(work, struct gelic_card, tx_timeout_task); - struct net_device *netdev = card->netdev[GELIC_PORT_ETHERNET]; + struct net_device *netdev = card->netdev[GELIC_PORT_ETHERNET_0]; dev_info(ctodev(card), "%s:Timed out. Restarting... \n", __func__); @@ -1531,10 +1594,10 @@ static struct gelic_card * __devinit gelic_alloc_card_net(struct net_device **ne /* gelic_port */ port->netdev = *netdev; port->card = card; - port->type = GELIC_PORT_ETHERNET; + port->type = GELIC_PORT_ETHERNET_0; /* gelic_card */ - card->netdev[GELIC_PORT_ETHERNET] = *netdev; + card->netdev[GELIC_PORT_ETHERNET_0] = *netdev; INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task); init_waitqueue_head(&card->waitq); @@ -1554,9 +1617,9 @@ static void __devinit gelic_card_get_vlan_info(struct gelic_card *card) int tx; int rx; } vlan_id_ix[2] = { - [GELIC_PORT_ETHERNET] = { - .tx = GELIC_LV1_VLAN_TX_ETHERNET, - .rx = GELIC_LV1_VLAN_RX_ETHERNET + [GELIC_PORT_ETHERNET_0] = { + .tx = GELIC_LV1_VLAN_TX_ETHERNET_0, + .rx = GELIC_LV1_VLAN_RX_ETHERNET_0 }, [GELIC_PORT_WIRELESS] = { .tx = GELIC_LV1_VLAN_TX_WIRELESS, @@ -1601,7 +1664,7 @@ static void __devinit gelic_card_get_vlan_info(struct gelic_card *card) i, card->vlan[i].tx, card->vlan[i].rx); } - if (card->vlan[GELIC_PORT_ETHERNET].tx) { + if (card->vlan[GELIC_PORT_ETHERNET_0].tx) { BUG_ON(!card->vlan[GELIC_PORT_WIRELESS].tx); card->vlan_required = 1; } else @@ -1657,6 +1720,8 @@ static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) /* get internal vlan info */ gelic_card_get_vlan_info(card); + card->link_mode = GELIC_LV1_ETHER_AUTO_NEG; + /* setup interrupt */ result = lv1_net_set_interrupt_status_indicator(bus_id(card), dev_id(card), @@ -1773,6 +1838,9 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) struct net_device *netdev0; pr_debug("%s: called\n", __func__); + /* set auto-negotiation */ + gelic_card_set_link_mode(card, GELIC_LV1_ETHER_AUTO_NEG); + #ifdef CONFIG_GELIC_WIRELESS gelic_wl_driver_remove(card); #endif @@ -1790,7 +1858,7 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) gelic_card_free_chain(card, card->tx_top); gelic_card_free_chain(card, card->rx_top); - netdev0 = card->netdev[GELIC_PORT_ETHERNET]; + netdev0 = card->netdev[GELIC_PORT_ETHERNET_0]; /* disconnect event port */ free_irq(card->irq, card); netdev0->irq = NO_IRQ; diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index 8b413868bbe..32521ae5e82 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -186,7 +186,7 @@ enum gelic_lv1_net_control_code { GELIC_LV1_GET_CHANNEL = 6, GELIC_LV1_POST_WLAN_CMD = 9, GELIC_LV1_GET_WLAN_CMD_RESULT = 10, - GELIC_LV1_GET_WLAN_EVENT = 11 + GELIC_LV1_GET_WLAN_EVENT = 11, }; /* for GELIC_LV1_SET_WOL */ @@ -217,24 +217,29 @@ enum gelic_lv1_ether_port_status { GELIC_LV1_ETHER_SPEED_10 = 0x0000000000000010L, GELIC_LV1_ETHER_SPEED_100 = 0x0000000000000020L, GELIC_LV1_ETHER_SPEED_1000 = 0x0000000000000040L, - GELIC_LV1_ETHER_SPEED_MASK = 0x0000000000000070L + GELIC_LV1_ETHER_SPEED_MASK = 0x0000000000000070L, }; enum gelic_lv1_vlan_index { /* for outgoing packets */ - GELIC_LV1_VLAN_TX_ETHERNET = 0x0000000000000002L, + GELIC_LV1_VLAN_TX_ETHERNET_0 = 0x0000000000000002L, GELIC_LV1_VLAN_TX_WIRELESS = 0x0000000000000003L, + /* for incoming packets */ - GELIC_LV1_VLAN_RX_ETHERNET = 0x0000000000000012L, - GELIC_LV1_VLAN_RX_WIRELESS = 0x0000000000000013L + GELIC_LV1_VLAN_RX_ETHERNET_0 = 0x0000000000000012L, + GELIC_LV1_VLAN_RX_WIRELESS = 0x0000000000000013L, +}; + +enum gelic_lv1_phy { + GELIC_LV1_PHY_ETHERNET_0 = 0x0000000000000002L, }; /* size of hardware part of gelic descriptor */ #define GELIC_DESCR_SIZE (32) enum gelic_port_type { - GELIC_PORT_ETHERNET = 0, - GELIC_PORT_WIRELESS = 1, + GELIC_PORT_ETHERNET_0 = 0, + GELIC_PORT_WIRELESS = 1, GELIC_PORT_MAX }; @@ -302,6 +307,8 @@ struct gelic_card { atomic_t users; u64 ether_port_status; + int link_mode; + /* original address returned by kzalloc */ void *unalign; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 4c610511eb4..e3e6bc917c8 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -1969,8 +1969,8 @@ static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev) struct ql_rcv_buf_cb *lrg_buf_cb; struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; - if ((qdev->lrg_buf_free_count >= 8) - && (qdev->lrg_buf_release_cnt >= 16)) { + if ((qdev->lrg_buf_free_count >= 8) && + (qdev->lrg_buf_release_cnt >= 16)) { if (qdev->lrg_buf_skb_check) if (!ql_populate_free_queue(qdev)) @@ -1978,8 +1978,8 @@ static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev) lrg_buf_q_ele = qdev->lrg_buf_next_free; - while ((qdev->lrg_buf_release_cnt >= 16) - && (qdev->lrg_buf_free_count >= 8)) { + while ((qdev->lrg_buf_release_cnt >= 16) && + (qdev->lrg_buf_free_count >= 8)) { for (i = 0; i < 8; i++) { lrg_buf_cb = diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 7692299e782..707b391afa0 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2347,8 +2347,8 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev, pci_alloc_consistent(qdev->pdev, tx_ring->wq_size, &tx_ring->wq_base_dma); - if ((tx_ring->wq_base == NULL) - || tx_ring->wq_base_dma & WQ_ADDR_ALIGN) { + if ((tx_ring->wq_base == NULL) || + tx_ring->wq_base_dma & WQ_ADDR_ALIGN) { QPRINTK(qdev, IFUP, ERR, "tx_ring alloc failed.\n"); return -ENOMEM; } diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 0f30ea4e97e..f03e2e4a15a 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -958,8 +958,7 @@ static void r6040_multicast_list(struct net_device *dev) } /* Too many multicast addresses * accept all traffic */ - else if ((dev->mc_count > MCAST_MAX) - || (dev->flags & IFF_ALLMULTI)) + else if ((dev->mc_count > MCAST_MAX) || (dev->flags & IFF_ALLMULTI)) reg |= 0x0020; iowrite16(reg, ioaddr); diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 98f6c51b760..acfc5a3aa49 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -794,7 +794,7 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; unsigned int i; - static struct { + static const struct { u32 opt; u16 reg; u8 mask; @@ -1277,7 +1277,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, * * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec */ - const struct { + static const struct { u32 mask; u32 val; int mac_version; @@ -1351,7 +1351,7 @@ struct phy_reg { u16 val; }; -static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len) +static void rtl_phy_write(void __iomem *ioaddr, const struct phy_reg *regs, int len) { while (len-- > 0) { mdio_write(ioaddr, regs->reg, regs->val); @@ -1361,7 +1361,7 @@ static void rtl_phy_write(void __iomem *ioaddr, struct phy_reg *regs, int len) static void rtl8169s_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, { 0x06, 0x006e }, { 0x08, 0x0708 }, @@ -1428,7 +1428,7 @@ static void rtl8169s_hw_phy_config(void __iomem *ioaddr) static void rtl8169sb_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0002 }, { 0x01, 0x90d0 }, { 0x1f, 0x0000 } @@ -1457,7 +1457,7 @@ static void rtl8169scd_hw_phy_config_quirk(struct rtl8169_private *tp, static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp, void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, { 0x04, 0x0000 }, { 0x03, 0x00a1 }, @@ -1504,7 +1504,7 @@ static void rtl8169scd_hw_phy_config(struct rtl8169_private *tp, static void rtl8169sce_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, { 0x04, 0x0000 }, { 0x03, 0x00a1 }, @@ -1557,7 +1557,7 @@ static void rtl8169sce_hw_phy_config(void __iomem *ioaddr) static void rtl8168bb_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x10, 0xf41b }, { 0x1f, 0x0000 } }; @@ -1570,7 +1570,7 @@ static void rtl8168bb_hw_phy_config(void __iomem *ioaddr) static void rtl8168bef_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, { 0x10, 0xf41b }, { 0x1f, 0x0000 } @@ -1581,7 +1581,7 @@ static void rtl8168bef_hw_phy_config(void __iomem *ioaddr) static void rtl8168cp_1_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0000 }, { 0x1d, 0x0f00 }, { 0x1f, 0x0002 }, @@ -1594,7 +1594,7 @@ static void rtl8168cp_1_hw_phy_config(void __iomem *ioaddr) static void rtl8168cp_2_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, { 0x1d, 0x3d98 }, { 0x1f, 0x0000 } @@ -1609,7 +1609,7 @@ static void rtl8168cp_2_hw_phy_config(void __iomem *ioaddr) static void rtl8168c_1_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, { 0x12, 0x2300 }, { 0x1f, 0x0002 }, @@ -1638,7 +1638,7 @@ static void rtl8168c_1_hw_phy_config(void __iomem *ioaddr) static void rtl8168c_2_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, { 0x12, 0x2300 }, { 0x03, 0x802f }, @@ -1666,7 +1666,7 @@ static void rtl8168c_2_hw_phy_config(void __iomem *ioaddr) static void rtl8168c_3_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0001 }, { 0x12, 0x2300 }, { 0x1d, 0x3d98 }, @@ -1693,7 +1693,7 @@ static void rtl8168c_4_hw_phy_config(void __iomem *ioaddr) static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) { - static struct phy_reg phy_reg_init_0[] = { + static const struct phy_reg phy_reg_init_0[] = { { 0x1f, 0x0001 }, { 0x06, 0x4064 }, { 0x07, 0x2863 }, @@ -1712,14 +1712,14 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) { 0x1a, 0x05ad }, { 0x14, 0x94c0 } }; - static struct phy_reg phy_reg_init_1[] = { + static const struct phy_reg phy_reg_init_1[] = { { 0x1f, 0x0002 }, { 0x06, 0x5561 }, { 0x1f, 0x0005 }, { 0x05, 0x8332 }, { 0x06, 0x5561 } }; - static struct phy_reg phy_reg_init_2[] = { + static const struct phy_reg phy_reg_init_2[] = { { 0x1f, 0x0005 }, { 0x05, 0xffc2 }, { 0x1f, 0x0005 }, @@ -2084,7 +2084,7 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) rtl_phy_write(ioaddr, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1)); if (rtl8168d_efuse_read(ioaddr, 0x01) == 0xb1) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0002 }, { 0x05, 0x669a }, { 0x1f, 0x0005 }, @@ -2099,7 +2099,7 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) val = mdio_read(ioaddr, 0x0d); if ((val & 0x00ff) != 0x006c) { - u32 set[] = { + static const u32 set[] = { 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c }; @@ -2112,7 +2112,7 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) mdio_write(ioaddr, 0x0d, val | set[i]); } } else { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0002 }, { 0x05, 0x6662 }, { 0x1f, 0x0005 }, @@ -2136,7 +2136,7 @@ static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr) static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr) { - static struct phy_reg phy_reg_init_0[] = { + static const struct phy_reg phy_reg_init_0[] = { { 0x1f, 0x0001 }, { 0x06, 0x4064 }, { 0x07, 0x2863 }, @@ -2161,7 +2161,7 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr) { 0x05, 0x8332 }, { 0x06, 0x5561 } }; - static struct phy_reg phy_reg_init_1[] = { + static const struct phy_reg phy_reg_init_1[] = { { 0x1f, 0x0005 }, { 0x05, 0xffc2 }, { 0x1f, 0x0005 }, @@ -2477,7 +2477,7 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr) rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0)); if (rtl8168d_efuse_read(ioaddr, 0x01) == 0xb1) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0002 }, { 0x05, 0x669a }, { 0x1f, 0x0005 }, @@ -2505,7 +2505,7 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr) mdio_write(ioaddr, 0x0d, val | set[i]); } } else { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0002 }, { 0x05, 0x2642 }, { 0x1f, 0x0005 }, @@ -2531,7 +2531,7 @@ static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr) static void rtl8168d_3_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0002 }, { 0x10, 0x0008 }, { 0x0d, 0x006c }, @@ -2592,7 +2592,7 @@ static void rtl8168d_3_hw_phy_config(void __iomem *ioaddr) static void rtl8102e_hw_phy_config(void __iomem *ioaddr) { - struct phy_reg phy_reg_init[] = { + static const struct phy_reg phy_reg_init[] = { { 0x1f, 0x0003 }, { 0x08, 0x441d }, { 0x01, 0x9100 }, @@ -3235,6 +3235,10 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev) flush_scheduled_work(); unregister_netdev(dev); + + /* restore original MAC address */ + rtl_rar_set(tp, dev->perm_addr); + rtl_disable_msi(pdev, tp); rtl8169_release_board(pdev, dev, tp->mmio_addr); pci_set_drvdata(pdev, NULL); @@ -3384,7 +3388,7 @@ static void rtl_set_rx_max_size(void __iomem *ioaddr, unsigned int rx_buf_sz) static void rtl8169_set_magic_reg(void __iomem *ioaddr, unsigned mac_version) { - struct { + static const struct { u32 mac_version; u32 clk; u32 val; @@ -3508,7 +3512,7 @@ struct ephy_info { u16 bits; }; -static void rtl_ephy_init(void __iomem *ioaddr, struct ephy_info *e, int len) +static void rtl_ephy_init(void __iomem *ioaddr, const struct ephy_info *e, int len) { u16 w; @@ -3579,7 +3583,7 @@ static void __rtl_hw_start_8168cp(void __iomem *ioaddr, struct pci_dev *pdev) static void rtl_hw_start_8168cp_1(void __iomem *ioaddr, struct pci_dev *pdev) { - static struct ephy_info e_info_8168cp[] = { + static const struct ephy_info e_info_8168cp[] = { { 0x01, 0, 0x0001 }, { 0x02, 0x0800, 0x1000 }, { 0x03, 0, 0x0042 }, @@ -3623,7 +3627,7 @@ static void rtl_hw_start_8168cp_3(void __iomem *ioaddr, struct pci_dev *pdev) static void rtl_hw_start_8168c_1(void __iomem *ioaddr, struct pci_dev *pdev) { - static struct ephy_info e_info_8168c_1[] = { + static const struct ephy_info e_info_8168c_1[] = { { 0x02, 0x0800, 0x1000 }, { 0x03, 0, 0x0002 }, { 0x06, 0x0080, 0x0000 } @@ -3640,7 +3644,7 @@ static void rtl_hw_start_8168c_1(void __iomem *ioaddr, struct pci_dev *pdev) static void rtl_hw_start_8168c_2(void __iomem *ioaddr, struct pci_dev *pdev) { - static struct ephy_info e_info_8168c_2[] = { + static const struct ephy_info e_info_8168c_2[] = { { 0x01, 0, 0x0001 }, { 0x03, 0x0400, 0x0220 } }; @@ -3783,7 +3787,7 @@ static void rtl_hw_start_8168(struct net_device *dev) static void rtl_hw_start_8102e_1(void __iomem *ioaddr, struct pci_dev *pdev) { - static struct ephy_info e_info_8102e_1[] = { + static const struct ephy_info e_info_8102e_1[] = { { 0x01, 0, 0x6e65 }, { 0x02, 0, 0x091f }, { 0x03, 0, 0xc2f9 }, @@ -4759,8 +4763,8 @@ static void rtl_set_rx_mode(struct net_device *dev) AcceptBroadcast | AcceptMulticast | AcceptMyPhys | AcceptAllPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to filter perfectly -- accept all multicasts. */ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; mc_filter[1] = mc_filter[0] = 0xffffffff; @@ -4880,6 +4884,9 @@ static void rtl_shutdown(struct pci_dev *pdev) rtl8169_net_suspend(dev); + /* restore original MAC address */ + rtl_rar_set(tp, dev->perm_addr); + spin_lock_irq(&tp->lock); rtl8169_asic_down(ioaddr); diff --git a/drivers/net/s6gmac.c b/drivers/net/s6gmac.c index d81706e91aa..45f26344b36 100644 --- a/drivers/net/s6gmac.c +++ b/drivers/net/s6gmac.c @@ -373,9 +373,9 @@ struct s6gmac { static void s6gmac_rx_fillfifo(struct s6gmac *pd) { struct sk_buff *skb; - while ((((u8)(pd->rx_skb_i - pd->rx_skb_o)) < S6_NUM_RX_SKB) - && (!s6dmac_fifo_full(pd->rx_dma, pd->rx_chan)) - && (skb = dev_alloc_skb(S6_MAX_FRLEN + 2))) { + while ((((u8)(pd->rx_skb_i - pd->rx_skb_o)) < S6_NUM_RX_SKB) && + (!s6dmac_fifo_full(pd->rx_dma, pd->rx_chan)) && + (skb = dev_alloc_skb(S6_MAX_FRLEN + 2))) { pd->rx_skb[(pd->rx_skb_i++) % S6_NUM_RX_SKB] = skb; s6dmac_put_fifo_cache(pd->rx_dma, pd->rx_chan, pd->io, (u32)skb->data, S6_MAX_FRLEN); diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index b7e0eb40a8b..e35050322f9 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -428,9 +428,9 @@ static void _sc92031_set_mar(struct net_device *dev) void __iomem *port_base = priv->port_base; u32 mar0 = 0, mar1 = 0; - if ((dev->flags & IFF_PROMISC) - || dev->mc_count > multicast_filter_limit - || (dev->flags & IFF_ALLMULTI)) + if ((dev->flags & IFF_PROMISC) || + dev->mc_count > multicast_filter_limit || + (dev->flags & IFF_ALLMULTI)) mar0 = mar1 = 0xffffffff; else if (dev->flags & IFF_MULTICAST) { struct dev_mc_list *mc_list; @@ -777,10 +777,10 @@ static void _sc92031_rx_tasklet(struct net_device *dev) rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN; - if (unlikely(rx_status == 0 - || rx_size > (MAX_ETH_FRAME_SIZE + 4) - || rx_size < 16 - || !(rx_status & RxStatesOK))) { + if (unlikely(rx_status == 0 || + rx_size > (MAX_ETH_FRAME_SIZE + 4) || + rx_size < 16 || + !(rx_status & RxStatesOK))) { _sc92031_rx_tasklet_error(dev, rx_status, rx_size); break; } diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig index 260aafaac23..a65c9863839 100644 --- a/drivers/net/sfc/Kconfig +++ b/drivers/net/sfc/Kconfig @@ -1,5 +1,5 @@ config SFC - tristate "Solarflare Solarstorm SFC4000 support" + tristate "Solarflare Solarstorm SFC4000/SFC9000-family support" depends on PCI && INET select MDIO select CRC32 @@ -7,15 +7,16 @@ config SFC select I2C_ALGOBIT help This driver supports 10-gigabit Ethernet cards based on - the Solarflare Communications Solarstorm SFC4000 controller. + the Solarflare Communications Solarstorm SFC4000 and + SFC9000-family controllers. To compile this driver as a module, choose M here. The module will be called sfc. config SFC_MTD - bool "Solarflare Solarstorm SFC4000 flash MTD support" + bool "Solarflare Solarstorm SFC4000/SFC9000-family MTD support" depends on SFC && MTD && !(SFC=y && MTD=m) default y help - This exposes the on-board flash memory as an MTD device (e.g. - /dev/mtd1). This makes it possible to upload new boot code - to the NIC. + This exposes the on-board flash memory as MTD devices (e.g. + /dev/mtd1). This makes it possible to upload new firmware + to the NIC. diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile index 7b52fe10d38..1047b19c60a 100644 --- a/drivers/net/sfc/Makefile +++ b/drivers/net/sfc/Makefile @@ -1,6 +1,7 @@ -sfc-y += efx.o falcon.o tx.o rx.o falcon_gmac.o \ - falcon_xmac.o selftest.o ethtool.o qt202x_phy.o \ - mdio_10g.o tenxpress.o falcon_boards.o +sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o \ + falcon_gmac.o falcon_xmac.o mcdi_mac.o \ + selftest.o ethtool.o qt202x_phy.o mdio_10g.o \ + tenxpress.o falcon_boards.o mcdi.o mcdi_phy.o sfc-$(CONFIG_SFC_MTD) += mtd.o obj-$(CONFIG_SFC) += sfc.o diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h index 6ad909bba95..098ac2ad757 100644 --- a/drivers/net/sfc/bitfield.h +++ b/drivers/net/sfc/bitfield.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -37,6 +37,8 @@ #define EFX_DWORD_2_WIDTH 32 #define EFX_DWORD_3_LBN 96 #define EFX_DWORD_3_WIDTH 32 +#define EFX_QWORD_0_LBN 0 +#define EFX_QWORD_0_WIDTH 64 /* Specified attribute (e.g. LBN) of the specified field */ #define EFX_VAL(field, attribute) field ## _ ## attribute diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 4787faaf30c..f983e3b507c 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2008 Solarflare Communications Inc. + * Copyright 2005-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -23,7 +23,9 @@ #include "net_driver.h" #include "efx.h" #include "mdio_10g.h" -#include "falcon.h" +#include "nic.h" + +#include "mcdi.h" /************************************************************************** * @@ -36,15 +38,32 @@ const unsigned int efx_loopback_mode_max = LOOPBACK_MAX; const char *efx_loopback_mode_names[] = { [LOOPBACK_NONE] = "NONE", + [LOOPBACK_DATA] = "DATAPATH", [LOOPBACK_GMAC] = "GMAC", [LOOPBACK_XGMII] = "XGMII", [LOOPBACK_XGXS] = "XGXS", [LOOPBACK_XAUI] = "XAUI", + [LOOPBACK_GMII] = "GMII", + [LOOPBACK_SGMII] = "SGMII", + [LOOPBACK_XGBR] = "XGBR", + [LOOPBACK_XFI] = "XFI", + [LOOPBACK_XAUI_FAR] = "XAUI_FAR", + [LOOPBACK_GMII_FAR] = "GMII_FAR", + [LOOPBACK_SGMII_FAR] = "SGMII_FAR", + [LOOPBACK_XFI_FAR] = "XFI_FAR", [LOOPBACK_GPHY] = "GPHY", [LOOPBACK_PHYXS] = "PHYXS", [LOOPBACK_PCS] = "PCS", [LOOPBACK_PMAPMD] = "PMA/PMD", - [LOOPBACK_NETWORK] = "NETWORK", + [LOOPBACK_XPORT] = "XPORT", + [LOOPBACK_XGMII_WS] = "XGMII_WS", + [LOOPBACK_XAUI_WS] = "XAUI_WS", + [LOOPBACK_XAUI_WS_FAR] = "XAUI_WS_FAR", + [LOOPBACK_XAUI_WS_NEAR] = "XAUI_WS_NEAR", + [LOOPBACK_GMII_WS] = "GMII_WS", + [LOOPBACK_XFI_WS] = "XFI_WS", + [LOOPBACK_XFI_WS_FAR] = "XFI_WS_FAR", + [LOOPBACK_PHYXS_WS] = "PHYXS_WS", }; /* Interrupt mode names (see INT_MODE())) */ @@ -67,6 +86,7 @@ const char *efx_reset_type_names[] = { [RESET_TYPE_RX_DESC_FETCH] = "RX_DESC_FETCH", [RESET_TYPE_TX_DESC_FETCH] = "TX_DESC_FETCH", [RESET_TYPE_TX_SKIP] = "TX_SKIP", + [RESET_TYPE_MC_FAILURE] = "MC_FAILURE", }; #define EFX_MAX_MTU (9 * 1024) @@ -186,7 +206,8 @@ static void efx_fini_channels(struct efx_nic *efx); #define EFX_ASSERT_RESET_SERIALISED(efx) \ do { \ - if (efx->state == STATE_RUNNING) \ + if ((efx->state == STATE_RUNNING) || \ + (efx->state == STATE_DISABLED)) \ ASSERT_RTNL(); \ } while (0) @@ -212,7 +233,7 @@ static int efx_process_channel(struct efx_channel *channel, int rx_quota) !channel->enabled)) return 0; - rx_packets = falcon_process_eventq(channel, rx_quota); + rx_packets = efx_nic_process_eventq(channel, rx_quota); if (rx_packets == 0) return 0; @@ -244,7 +265,7 @@ static inline void efx_channel_processed(struct efx_channel *channel) channel->work_pending = false; smp_wmb(); - falcon_eventq_read_ack(channel); + efx_nic_eventq_read_ack(channel); } /* NAPI poll handler @@ -273,14 +294,14 @@ static int efx_poll(struct napi_struct *napi, int budget) irq_adapt_low_thresh)) { if (channel->irq_moderation > 1) { channel->irq_moderation -= 1; - falcon_set_int_moderation(channel); + efx->type->push_irq_moderation(channel); } } else if (unlikely(channel->irq_mod_score > irq_adapt_high_thresh)) { if (channel->irq_moderation < efx->irq_rx_moderation) { channel->irq_moderation += 1; - falcon_set_int_moderation(channel); + efx->type->push_irq_moderation(channel); } } channel->irq_count = 0; @@ -315,7 +336,7 @@ void efx_process_channel_now(struct efx_channel *channel) BUG_ON(!channel->enabled); /* Disable interrupts and wait for ISRs to complete */ - falcon_disable_interrupts(efx); + efx_nic_disable_interrupts(efx); if (efx->legacy_irq) synchronize_irq(efx->legacy_irq); if (channel->irq) @@ -332,7 +353,7 @@ void efx_process_channel_now(struct efx_channel *channel) efx_channel_processed(channel); napi_enable(&channel->napi_str); - falcon_enable_interrupts(efx); + efx_nic_enable_interrupts(efx); } /* Create event queue @@ -344,7 +365,7 @@ static int efx_probe_eventq(struct efx_channel *channel) { EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel); - return falcon_probe_eventq(channel); + return efx_nic_probe_eventq(channel); } /* Prepare channel's event queue */ @@ -354,21 +375,21 @@ static void efx_init_eventq(struct efx_channel *channel) channel->eventq_read_ptr = 0; - falcon_init_eventq(channel); + efx_nic_init_eventq(channel); } static void efx_fini_eventq(struct efx_channel *channel) { EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel); - falcon_fini_eventq(channel); + efx_nic_fini_eventq(channel); } static void efx_remove_eventq(struct efx_channel *channel) { EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel); - falcon_remove_eventq(channel); + efx_nic_remove_eventq(channel); } /************************************************************************** @@ -534,7 +555,7 @@ static void efx_fini_channels(struct efx_nic *efx) EFX_ASSERT_RESET_SERIALISED(efx); BUG_ON(efx->port_enabled); - rc = falcon_flush_queues(efx); + rc = efx_nic_flush_queues(efx); if (rc) EFX_ERR(efx, "failed to flush queues\n"); else @@ -582,7 +603,7 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay) * netif_carrier_on/off) of the link status, and also maintains the * link status's stop on the port's TX queue. */ -static void efx_link_status_changed(struct efx_nic *efx) +void efx_link_status_changed(struct efx_nic *efx) { struct efx_link_state *link_state = &efx->link_state; @@ -619,16 +640,49 @@ static void efx_link_status_changed(struct efx_nic *efx) } +void efx_link_set_advertising(struct efx_nic *efx, u32 advertising) +{ + efx->link_advertising = advertising; + if (advertising) { + if (advertising & ADVERTISED_Pause) + efx->wanted_fc |= (EFX_FC_TX | EFX_FC_RX); + else + efx->wanted_fc &= ~(EFX_FC_TX | EFX_FC_RX); + if (advertising & ADVERTISED_Asym_Pause) + efx->wanted_fc ^= EFX_FC_TX; + } +} + +void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type wanted_fc) +{ + efx->wanted_fc = wanted_fc; + if (efx->link_advertising) { + if (wanted_fc & EFX_FC_RX) + efx->link_advertising |= (ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + else + efx->link_advertising &= ~(ADVERTISED_Pause | + ADVERTISED_Asym_Pause); + if (wanted_fc & EFX_FC_TX) + efx->link_advertising ^= ADVERTISED_Asym_Pause; + } +} + static void efx_fini_port(struct efx_nic *efx); -/* This call reinitialises the MAC to pick up new PHY settings. The - * caller must hold the mac_lock */ -void __efx_reconfigure_port(struct efx_nic *efx) +/* Push loopback/power/transmit disable settings to the PHY, and reconfigure + * the MAC appropriately. All other PHY configuration changes are pushed + * through phy_op->set_settings(), and pushed asynchronously to the MAC + * through efx_monitor(). + * + * Callers must hold the mac_lock + */ +int __efx_reconfigure_port(struct efx_nic *efx) { - WARN_ON(!mutex_is_locked(&efx->mac_lock)); + enum efx_phy_mode phy_mode; + int rc; - EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n", - raw_smp_processor_id()); + WARN_ON(!mutex_is_locked(&efx->mac_lock)); /* Serialise the promiscuous flag with efx_set_multicast_list. */ if (efx_dev_registered(efx)) { @@ -636,61 +690,48 @@ void __efx_reconfigure_port(struct efx_nic *efx) netif_addr_unlock_bh(efx->net_dev); } - falcon_deconfigure_mac_wrapper(efx); - - /* Reconfigure the PHY, disabling transmit in mac level loopback. */ + /* Disable PHY transmit in mac level loopbacks */ + phy_mode = efx->phy_mode; if (LOOPBACK_INTERNAL(efx)) efx->phy_mode |= PHY_MODE_TX_DISABLED; else efx->phy_mode &= ~PHY_MODE_TX_DISABLED; - efx->phy_op->reconfigure(efx); - if (falcon_switch_mac(efx)) - goto fail; - - efx->mac_op->reconfigure(efx); + rc = efx->type->reconfigure_port(efx); - /* Inform kernel of loss/gain of carrier */ - efx_link_status_changed(efx); - return; + if (rc) + efx->phy_mode = phy_mode; -fail: - EFX_ERR(efx, "failed to reconfigure MAC\n"); - efx->port_enabled = false; - efx_fini_port(efx); + return rc; } /* Reinitialise the MAC to pick up new PHY settings, even if the port is * disabled. */ -void efx_reconfigure_port(struct efx_nic *efx) +int efx_reconfigure_port(struct efx_nic *efx) { + int rc; + EFX_ASSERT_RESET_SERIALISED(efx); mutex_lock(&efx->mac_lock); - __efx_reconfigure_port(efx); + rc = __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); -} - -/* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all() - * we don't efx_reconfigure_port() if the port is disabled. Care is taken - * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */ -static void efx_phy_work(struct work_struct *data) -{ - struct efx_nic *efx = container_of(data, struct efx_nic, phy_work); - mutex_lock(&efx->mac_lock); - if (efx->port_enabled) - __efx_reconfigure_port(efx); - mutex_unlock(&efx->mac_lock); + return rc; } +/* Asynchronous work item for changing MAC promiscuity and multicast + * hash. Avoid a drain/rx_ingress enable by reconfiguring the current + * MAC directly. */ static void efx_mac_work(struct work_struct *data) { struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); mutex_lock(&efx->mac_lock); - if (efx->port_enabled) - efx->mac_op->irq(efx); + if (efx->port_enabled) { + efx->type->push_multicast_hash(efx); + efx->mac_op->reconfigure(efx); + } mutex_unlock(&efx->mac_lock); } @@ -700,8 +741,8 @@ static int efx_probe_port(struct efx_nic *efx) EFX_LOG(efx, "create port\n"); - /* Connect up MAC/PHY operations table and read MAC address */ - rc = falcon_probe_port(efx); + /* Connect up MAC/PHY operations table */ + rc = efx->type->probe_port(efx); if (rc) goto err; @@ -736,29 +777,33 @@ static int efx_init_port(struct efx_nic *efx) EFX_LOG(efx, "init port\n"); - rc = efx->phy_op->init(efx); - if (rc) - return rc; mutex_lock(&efx->mac_lock); - efx->phy_op->reconfigure(efx); - rc = falcon_switch_mac(efx); - mutex_unlock(&efx->mac_lock); + + rc = efx->phy_op->init(efx); if (rc) - goto fail; - efx->mac_op->reconfigure(efx); + goto fail1; efx->port_initialized = true; - efx_stats_enable(efx); + + /* Reconfigure the MAC before creating dma queues (required for + * Falcon/A1 where RX_INGR_EN/TX_DRAIN_EN isn't supported) */ + efx->mac_op->reconfigure(efx); + + /* Ensure the PHY advertises the correct flow control settings */ + rc = efx->phy_op->reconfigure(efx); + if (rc) + goto fail2; + + mutex_unlock(&efx->mac_lock); return 0; -fail: +fail2: efx->phy_op->fini(efx); +fail1: + mutex_unlock(&efx->mac_lock); return rc; } -/* Allow efx_reconfigure_port() to be scheduled, and close the window - * between efx_stop_port and efx_flush_all whereby a previously scheduled - * efx_phy_work()/efx_mac_work() may have been cancelled */ static void efx_start_port(struct efx_nic *efx) { EFX_LOG(efx, "start port\n"); @@ -766,15 +811,16 @@ static void efx_start_port(struct efx_nic *efx) mutex_lock(&efx->mac_lock); efx->port_enabled = true; - __efx_reconfigure_port(efx); - efx->mac_op->irq(efx); + + /* efx_mac_work() might have been scheduled after efx_stop_port(), + * and then cancelled by efx_flush_all() */ + efx->type->push_multicast_hash(efx); + efx->mac_op->reconfigure(efx); + mutex_unlock(&efx->mac_lock); } -/* Prevent efx_phy_work, efx_mac_work, and efx_monitor() from executing, - * and efx_set_multicast_list() from scheduling efx_phy_work. efx_phy_work - * and efx_mac_work may still be scheduled via NAPI processing until - * efx_flush_all() is called */ +/* Prevent efx_mac_work() and efx_monitor() from working */ static void efx_stop_port(struct efx_nic *efx) { EFX_LOG(efx, "stop port\n"); @@ -797,7 +843,6 @@ static void efx_fini_port(struct efx_nic *efx) if (!efx->port_initialized) return; - efx_stats_disable(efx); efx->phy_op->fini(efx); efx->port_initialized = false; @@ -809,7 +854,7 @@ static void efx_remove_port(struct efx_nic *efx) { EFX_LOG(efx, "destroying port\n"); - falcon_remove_port(efx); + efx->type->remove_port(efx); } /************************************************************************** @@ -1046,7 +1091,7 @@ static int efx_probe_nic(struct efx_nic *efx) EFX_LOG(efx, "creating NIC\n"); /* Carry out hardware-type specific initialisation */ - rc = falcon_probe_nic(efx); + rc = efx->type->probe(efx); if (rc) return rc; @@ -1067,7 +1112,7 @@ static void efx_remove_nic(struct efx_nic *efx) EFX_LOG(efx, "destroying NIC\n"); efx_remove_interrupts(efx); - falcon_remove_nic(efx); + efx->type->remove(efx); } /************************************************************************** @@ -1147,12 +1192,31 @@ static void efx_start_all(struct efx_nic *efx) efx_for_each_channel(channel, efx) efx_start_channel(channel); - falcon_enable_interrupts(efx); - - /* Start hardware monitor if we're in RUNNING */ - if (efx->state == STATE_RUNNING) + efx_nic_enable_interrupts(efx); + + /* Switch to event based MCDI completions after enabling interrupts. + * If a reset has been scheduled, then we need to stay in polled mode. + * Rather than serialising efx_mcdi_mode_event() [which sleeps] and + * reset_pending [modified from an atomic context], we instead guarantee + * that efx_mcdi_mode_poll() isn't reverted erroneously */ + efx_mcdi_mode_event(efx); + if (efx->reset_pending != RESET_TYPE_NONE) + efx_mcdi_mode_poll(efx); + + /* Start the hardware monitor if there is one. Otherwise (we're link + * event driven), we have to poll the PHY because after an event queue + * flush, we could have a missed a link state change */ + if (efx->type->monitor != NULL) { queue_delayed_work(efx->workqueue, &efx->monitor_work, efx_monitor_interval); + } else { + mutex_lock(&efx->mac_lock); + if (efx->phy_op->poll(efx)) + efx_link_status_changed(efx); + mutex_unlock(&efx->mac_lock); + } + + efx->type->start_stats(efx); } /* Flush all delayed work. Should only be called when no more delayed work @@ -1171,8 +1235,6 @@ static void efx_flush_all(struct efx_nic *efx) /* Stop scheduled port reconfigurations */ cancel_work_sync(&efx->mac_work); - cancel_work_sync(&efx->phy_work); - } /* Quiesce hardware and software without bringing the link down. @@ -1190,8 +1252,13 @@ static void efx_stop_all(struct efx_nic *efx) if (!efx->port_enabled) return; + efx->type->stop_stats(efx); + + /* Switch to MCDI polling on Siena before disabling interrupts */ + efx_mcdi_mode_poll(efx); + /* Disable interrupts and wait for ISR to complete */ - falcon_disable_interrupts(efx); + efx_nic_disable_interrupts(efx); if (efx->legacy_irq) synchronize_irq(efx->legacy_irq); efx_for_each_channel(channel, efx) { @@ -1208,15 +1275,9 @@ static void efx_stop_all(struct efx_nic *efx) * window to loose phy events */ efx_stop_port(efx); - /* Flush efx_phy_work, efx_mac_work, refill_workqueue, monitor_work */ + /* Flush efx_mac_work(), refill_workqueue, monitor_work */ efx_flush_all(efx); - /* Isolate the MAC from the TX and RX engines, so that queue - * flushes will complete in a timely fashion. */ - falcon_deconfigure_mac_wrapper(efx); - msleep(10); /* Let the Rx FIFO drain */ - falcon_drain_tx_fifo(efx); - /* Stop the kernel transmit interface late, so the watchdog * timer isn't ticking over the flush */ if (efx_dev_registered(efx)) { @@ -1236,19 +1297,6 @@ static void efx_remove_all(struct efx_nic *efx) efx_remove_nic(efx); } -/* A convinience function to safely flush all the queues */ -void efx_flush_queues(struct efx_nic *efx) -{ - EFX_ASSERT_RESET_SERIALISED(efx); - - efx_stop_all(efx); - - efx_fini_channels(efx); - efx_init_channels(efx); - - efx_start_all(efx); -} - /************************************************************************** * * Interrupt moderation @@ -1270,8 +1318,8 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs, { struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; - unsigned tx_ticks = irq_mod_ticks(tx_usecs, FALCON_IRQ_MOD_RESOLUTION); - unsigned rx_ticks = irq_mod_ticks(rx_usecs, FALCON_IRQ_MOD_RESOLUTION); + unsigned tx_ticks = irq_mod_ticks(tx_usecs, EFX_IRQ_MOD_RESOLUTION); + unsigned rx_ticks = irq_mod_ticks(rx_usecs, EFX_IRQ_MOD_RESOLUTION); EFX_ASSERT_RESET_SERIALISED(efx); @@ -1296,10 +1344,10 @@ static void efx_monitor(struct work_struct *data) { struct efx_nic *efx = container_of(data, struct efx_nic, monitor_work.work); - int rc; EFX_TRACE(efx, "hardware monitor executing on CPU %d\n", raw_smp_processor_id()); + BUG_ON(efx->type->monitor == NULL); /* If the mac_lock is already held then it is likely a port * reconfiguration is already in place, which will likely do @@ -1308,15 +1356,7 @@ static void efx_monitor(struct work_struct *data) goto out_requeue; if (!efx->port_enabled) goto out_unlock; - rc = falcon_board(efx)->monitor(efx); - if (rc) { - EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", - (rc == -ERANGE) ? "reported fault" : "failed"); - efx->phy_mode |= PHY_MODE_LOW_POWER; - falcon_sim_phy_event(efx); - } - efx->phy_op->poll(efx); - efx->mac_op->poll(efx); + efx->type->monitor(efx); out_unlock: mutex_unlock(&efx->mac_lock); @@ -1420,6 +1460,12 @@ static int efx_net_open(struct net_device *net_dev) return -EIO; if (efx->phy_mode & PHY_MODE_SPECIAL) return -EBUSY; + if (efx_mcdi_poll_reboot(efx) && efx_reset(efx, RESET_TYPE_ALL)) + return -EIO; + + /* Notify the kernel of the link state polled during driver load, + * before the monitor starts running */ + efx_link_status_changed(efx); efx_start_all(efx); return 0; @@ -1446,20 +1492,6 @@ static int efx_net_stop(struct net_device *net_dev) return 0; } -void efx_stats_disable(struct efx_nic *efx) -{ - spin_lock(&efx->stats_lock); - ++efx->stats_disable_count; - spin_unlock(&efx->stats_lock); -} - -void efx_stats_enable(struct efx_nic *efx) -{ - spin_lock(&efx->stats_lock); - --efx->stats_disable_count; - spin_unlock(&efx->stats_lock); -} - /* Context: process, dev_base_lock or RTNL held, non-blocking. */ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) { @@ -1467,17 +1499,9 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) struct efx_mac_stats *mac_stats = &efx->mac_stats; struct net_device_stats *stats = &net_dev->stats; - /* Update stats if possible, but do not wait if another thread - * is updating them or if MAC stats fetches are temporarily - * disabled; slightly stale stats are acceptable. - */ - if (!spin_trylock(&efx->stats_lock)) - return stats; - if (!efx->stats_disable_count) { - efx->mac_op->update_stats(efx); - falcon_update_nic_stats(efx); - } - spin_unlock(&efx->stats_lock); + spin_lock_bh(&efx->stats_lock); + efx->type->update_stats(efx); + spin_unlock_bh(&efx->stats_lock); stats->rx_packets = mac_stats->rx_packets; stats->tx_packets = mac_stats->tx_packets; @@ -1536,7 +1560,14 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu) EFX_LOG(efx, "changing MTU to %d\n", new_mtu); efx_fini_channels(efx); + + mutex_lock(&efx->mac_lock); + /* Reconfigure the MAC before enabling the dma queues so that + * the RX buffers don't overflow */ net_dev->mtu = new_mtu; + efx->mac_op->reconfigure(efx); + mutex_unlock(&efx->mac_lock); + efx_init_channels(efx); efx_start_all(efx); @@ -1560,7 +1591,9 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len); /* Reconfigure the MAC */ - efx_reconfigure_port(efx); + mutex_lock(&efx->mac_lock); + efx->mac_op->reconfigure(efx); + mutex_unlock(&efx->mac_lock); return 0; } @@ -1571,16 +1604,14 @@ static void efx_set_multicast_list(struct net_device *net_dev) struct efx_nic *efx = netdev_priv(net_dev); struct dev_mc_list *mc_list = net_dev->mc_list; union efx_multicast_hash *mc_hash = &efx->multicast_hash; - bool promiscuous = !!(net_dev->flags & IFF_PROMISC); - bool changed = (efx->promiscuous != promiscuous); u32 crc; int bit; int i; - efx->promiscuous = promiscuous; + efx->promiscuous = !!(net_dev->flags & IFF_PROMISC); /* Build multicast hash table */ - if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) { + if (efx->promiscuous || (net_dev->flags & IFF_ALLMULTI)) { memset(mc_hash, 0xff, sizeof(*mc_hash)); } else { memset(mc_hash, 0x00, sizeof(*mc_hash)); @@ -1590,17 +1621,17 @@ static void efx_set_multicast_list(struct net_device *net_dev) set_bit_le(bit, mc_hash->byte); mc_list = mc_list->next; } - } - if (!efx->port_enabled) - /* Delay pushing settings until efx_start_port() */ - return; - - if (changed) - queue_work(efx->workqueue, &efx->phy_work); + /* Broadcast packets go through the multicast hash filter. + * ether_crc_le() of the broadcast address is 0xbe2612ff + * so we always add bit 0xff to the mask. + */ + set_bit_le(0xff, mc_hash->byte); + } - /* Create and activate new global multicast hash table */ - falcon_set_multicast_hash(efx); + if (efx->port_enabled) + queue_work(efx->workqueue, &efx->mac_work); + /* Otherwise efx_start_port() will do this */ } static const struct net_device_ops efx_netdev_ops = { @@ -1729,21 +1760,18 @@ static void efx_unregister_netdev(struct efx_nic *efx) /* Tears down the entire software state and most of the hardware state * before reset. */ -void efx_reset_down(struct efx_nic *efx, enum reset_type method, - struct ethtool_cmd *ecmd) +void efx_reset_down(struct efx_nic *efx, enum reset_type method) { EFX_ASSERT_RESET_SERIALISED(efx); - efx_stats_disable(efx); efx_stop_all(efx); mutex_lock(&efx->mac_lock); mutex_lock(&efx->spi_lock); - efx->phy_op->get_settings(efx, ecmd); - efx_fini_channels(efx); if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) efx->phy_op->fini(efx); + efx->type->fini(efx); } /* This function will always ensure that the locks acquired in @@ -1751,79 +1779,67 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method, * that we were unable to reinitialise the hardware, and the * driver should be disabled. If ok is false, then the rx and tx * engines are not restarted, pending a RESET_DISABLE. */ -int efx_reset_up(struct efx_nic *efx, enum reset_type method, - struct ethtool_cmd *ecmd, bool ok) +int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) { int rc; EFX_ASSERT_RESET_SERIALISED(efx); - rc = falcon_init_nic(efx); + rc = efx->type->init(efx); if (rc) { EFX_ERR(efx, "failed to initialise NIC\n"); - ok = false; + goto fail; } + if (!ok) + goto fail; + if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) { - if (ok) { - rc = efx->phy_op->init(efx); - if (rc) - ok = false; - } - if (!ok) - efx->port_initialized = false; + rc = efx->phy_op->init(efx); + if (rc) + goto fail; + if (efx->phy_op->reconfigure(efx)) + EFX_ERR(efx, "could not restore PHY settings\n"); } - if (ok) { - efx_init_channels(efx); + efx->mac_op->reconfigure(efx); - if (efx->phy_op->set_settings(efx, ecmd)) - EFX_ERR(efx, "could not restore PHY settings\n"); - } + efx_init_channels(efx); + + mutex_unlock(&efx->spi_lock); + mutex_unlock(&efx->mac_lock); + + efx_start_all(efx); + + return 0; + +fail: + efx->port_initialized = false; mutex_unlock(&efx->spi_lock); mutex_unlock(&efx->mac_lock); - if (ok) { - efx_start_all(efx); - efx_stats_enable(efx); - } return rc; } -/* Reset the NIC as transparently as possible. Do not reset the PHY - * Note that the reset may fail, in which case the card will be left - * in a most-probably-unusable state. +/* Reset the NIC using the specified method. Note that the reset may + * fail, in which case the card will be left in an unusable state. * - * This function will sleep. You cannot reset from within an atomic - * state; use efx_schedule_reset() instead. - * - * Grabs the rtnl_lock. + * Caller must hold the rtnl_lock. */ -static int efx_reset(struct efx_nic *efx) +int efx_reset(struct efx_nic *efx, enum reset_type method) { - struct ethtool_cmd ecmd; - enum reset_type method = efx->reset_pending; - int rc = 0; - - /* Serialise with kernel interfaces */ - rtnl_lock(); - - /* If we're not RUNNING then don't reset. Leave the reset_pending - * flag set so that efx_pci_probe_main will be retried */ - if (efx->state != STATE_RUNNING) { - EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); - goto out_unlock; - } + int rc, rc2; + bool disabled; EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method)); - efx_reset_down(efx, method, &ecmd); + efx_reset_down(efx, method); - rc = falcon_reset_hw(efx, method); + rc = efx->type->reset(efx, method); if (rc) { EFX_ERR(efx, "failed to reset hardware\n"); - goto out_disable; + goto out; } /* Allow resets to be rescheduled. */ @@ -1835,25 +1851,22 @@ static int efx_reset(struct efx_nic *efx) * can respond to requests. */ pci_set_master(efx->pci_dev); +out: /* Leave device stopped if necessary */ - if (method == RESET_TYPE_DISABLE) { - efx_reset_up(efx, method, &ecmd, false); - rc = -EIO; - } else { - rc = efx_reset_up(efx, method, &ecmd, true); + disabled = rc || method == RESET_TYPE_DISABLE; + rc2 = efx_reset_up(efx, method, !disabled); + if (rc2) { + disabled = true; + if (!rc) + rc = rc2; } -out_disable: - if (rc) { + if (disabled) { EFX_ERR(efx, "has been disabled\n"); efx->state = STATE_DISABLED; - dev_close(efx->net_dev); } else { EFX_LOG(efx, "reset complete\n"); } - -out_unlock: - rtnl_unlock(); return rc; } @@ -1862,9 +1875,19 @@ out_unlock: */ static void efx_reset_work(struct work_struct *data) { - struct efx_nic *nic = container_of(data, struct efx_nic, reset_work); + struct efx_nic *efx = container_of(data, struct efx_nic, reset_work); - efx_reset(nic); + /* If we're not RUNNING then don't reset. Leave the reset_pending + * flag set so that efx_pci_probe_main will be retried */ + if (efx->state != STATE_RUNNING) { + EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); + return; + } + + rtnl_lock(); + if (efx_reset(efx, efx->reset_pending)) + dev_close(efx->net_dev); + rtnl_unlock(); } void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) @@ -1889,6 +1912,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) case RESET_TYPE_TX_SKIP: method = RESET_TYPE_INVISIBLE; break; + case RESET_TYPE_MC_FAILURE: default: method = RESET_TYPE_ALL; break; @@ -1902,6 +1926,10 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) efx->reset_pending = method; + /* efx_process_channel() will no longer read events once a + * reset is scheduled. So switch back to poll'd MCDI completions. */ + efx_mcdi_mode_poll(efx); + queue_work(reset_workqueue, &efx->reset_work); } @@ -1914,9 +1942,13 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) /* PCI device ID table */ static struct pci_device_id efx_pci_table[] __devinitdata = { {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID), - .driver_data = (unsigned long) &falcon_a_nic_type}, + .driver_data = (unsigned long) &falcon_a1_nic_type}, {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID), - .driver_data = (unsigned long) &falcon_b_nic_type}, + .driver_data = (unsigned long) &falcon_b0_nic_type}, + {PCI_DEVICE(EFX_VENDID_SFC, BETHPAGE_A_P_DEVID), + .driver_data = (unsigned long) &siena_a0_nic_type}, + {PCI_DEVICE(EFX_VENDID_SFC, SIENA_A_P_DEVID), + .driver_data = (unsigned long) &siena_a0_nic_type}, {0} /* end of list */ }; @@ -1937,19 +1969,16 @@ void efx_port_dummy_op_void(struct efx_nic *efx) {} void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) { } - -static struct efx_mac_operations efx_dummy_mac_operations = { - .reconfigure = efx_port_dummy_op_void, - .poll = efx_port_dummy_op_void, - .irq = efx_port_dummy_op_void, -}; +bool efx_port_dummy_op_poll(struct efx_nic *efx) +{ + return false; +} static struct efx_phy_operations efx_dummy_phy_operations = { .init = efx_port_dummy_op_int, - .reconfigure = efx_port_dummy_op_void, - .poll = efx_port_dummy_op_void, + .reconfigure = efx_port_dummy_op_int, + .poll = efx_port_dummy_op_poll, .fini = efx_port_dummy_op_void, - .clear_interrupt = efx_port_dummy_op_void, }; /************************************************************************** @@ -1972,8 +2001,11 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, /* Initialise common structures */ memset(efx, 0, sizeof(*efx)); spin_lock_init(&efx->biu_lock); - spin_lock_init(&efx->phy_lock); + mutex_init(&efx->mdio_lock); mutex_init(&efx->spi_lock); +#ifdef CONFIG_SFC_MTD + INIT_LIST_HEAD(&efx->mtd_list); +#endif INIT_WORK(&efx->reset_work, efx_reset_work); INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); efx->pci_dev = pci_dev; @@ -1985,12 +2017,10 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, efx->rx_checksum_enabled = true; spin_lock_init(&efx->netif_stop_lock); spin_lock_init(&efx->stats_lock); - efx->stats_disable_count = 1; mutex_init(&efx->mac_lock); - efx->mac_op = &efx_dummy_mac_operations; + efx->mac_op = type->default_mac_ops; efx->phy_op = &efx_dummy_phy_operations; efx->mdio.dev = net_dev; - INIT_WORK(&efx->phy_work, efx_phy_work); INIT_WORK(&efx->mac_work, efx_mac_work); atomic_set(&efx->netif_stop_count, 1); @@ -2058,9 +2088,10 @@ static void efx_fini_struct(struct efx_nic *efx) */ static void efx_pci_remove_main(struct efx_nic *efx) { - falcon_fini_interrupt(efx); + efx_nic_fini_interrupt(efx); efx_fini_channels(efx); efx_fini_port(efx); + efx->type->fini(efx); efx_fini_napi(efx); efx_remove_all(efx); } @@ -2120,7 +2151,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) if (rc) goto fail2; - rc = falcon_init_nic(efx); + rc = efx->type->init(efx); if (rc) { EFX_ERR(efx, "failed to initialise NIC\n"); goto fail3; @@ -2134,7 +2165,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) efx_init_channels(efx); - rc = falcon_init_interrupt(efx); + rc = efx_nic_init_interrupt(efx); if (rc) goto fail5; @@ -2144,6 +2175,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) efx_fini_channels(efx); efx_fini_port(efx); fail4: + efx->type->fini(efx); fail3: efx_fini_napi(efx); fail2: @@ -2173,9 +2205,11 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, net_dev = alloc_etherdev(sizeof(*efx)); if (!net_dev) return -ENOMEM; - net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG | + net_dev->features |= (type->offload_features | NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_GRO); + if (type->offload_features & NETIF_F_V6_CSUM) + net_dev->features |= NETIF_F_TSO6; /* Mask for features that also apply to VLAN devices */ net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_TSO); @@ -2227,9 +2261,8 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, goto fail4; } - /* Switch to the running state before we expose the device to - * the OS. This is to ensure that the initial gathering of - * MAC stats succeeds. */ + /* Switch to the running state before we expose the device to the OS, + * so that dev_open()|efx_start_all() will actually start the device */ efx->state = STATE_RUNNING; rc = efx_register_netdev(efx); @@ -2256,11 +2289,107 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, return rc; } +static int efx_pm_freeze(struct device *dev) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + + efx->state = STATE_FINI; + + netif_device_detach(efx->net_dev); + + efx_stop_all(efx); + efx_fini_channels(efx); + + return 0; +} + +static int efx_pm_thaw(struct device *dev) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + + efx->state = STATE_INIT; + + efx_init_channels(efx); + + mutex_lock(&efx->mac_lock); + efx->phy_op->reconfigure(efx); + mutex_unlock(&efx->mac_lock); + + efx_start_all(efx); + + netif_device_attach(efx->net_dev); + + efx->state = STATE_RUNNING; + + efx->type->resume_wol(efx); + + return 0; +} + +static int efx_pm_poweroff(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct efx_nic *efx = pci_get_drvdata(pci_dev); + + efx->type->fini(efx); + + efx->reset_pending = RESET_TYPE_NONE; + + pci_save_state(pci_dev); + return pci_set_power_state(pci_dev, PCI_D3hot); +} + +/* Used for both resume and restore */ +static int efx_pm_resume(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct efx_nic *efx = pci_get_drvdata(pci_dev); + int rc; + + rc = pci_set_power_state(pci_dev, PCI_D0); + if (rc) + return rc; + pci_restore_state(pci_dev); + rc = pci_enable_device(pci_dev); + if (rc) + return rc; + pci_set_master(efx->pci_dev); + rc = efx->type->reset(efx, RESET_TYPE_ALL); + if (rc) + return rc; + rc = efx->type->init(efx); + if (rc) + return rc; + efx_pm_thaw(dev); + return 0; +} + +static int efx_pm_suspend(struct device *dev) +{ + int rc; + + efx_pm_freeze(dev); + rc = efx_pm_poweroff(dev); + if (rc) + efx_pm_resume(dev); + return rc; +} + +static struct dev_pm_ops efx_pm_ops = { + .suspend = efx_pm_suspend, + .resume = efx_pm_resume, + .freeze = efx_pm_freeze, + .thaw = efx_pm_thaw, + .poweroff = efx_pm_poweroff, + .restore = efx_pm_resume, +}; + static struct pci_driver efx_pci_driver = { .name = EFX_DRIVER_NAME, .id_table = efx_pci_table, .probe = efx_pci_probe, .remove = efx_pci_remove, + .driver.pm = &efx_pm_ops, }; /************************************************************************** @@ -2324,8 +2453,8 @@ static void __exit efx_exit_module(void) module_init(efx_init_module); module_exit(efx_exit_module); -MODULE_AUTHOR("Michael Brown <mbrown@fensystems.co.uk> and " - "Solarflare Communications"); +MODULE_AUTHOR("Solarflare Communications and " + "Michael Brown <mbrown@fensystems.co.uk>"); MODULE_DESCRIPTION("Solarflare Communications network driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, efx_pci_table); diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index 3497b036f40..a615ac05153 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -18,6 +18,8 @@ #define FALCON_A_P_DEVID 0x0703 #define FALCON_A_S_DEVID 0x6703 #define FALCON_B_P_DEVID 0x0710 +#define BETHPAGE_A_P_DEVID 0x0803 +#define SIENA_A_P_DEVID 0x0813 /* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ #define EFX_MEM_BAR 2 @@ -56,15 +58,12 @@ extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay); /* Channels */ extern void efx_process_channel_now(struct efx_channel *channel); -extern void efx_flush_queues(struct efx_nic *efx); #define EFX_EVQ_SIZE 4096 #define EFX_EVQ_MASK (EFX_EVQ_SIZE - 1) /* Ports */ -extern void efx_stats_disable(struct efx_nic *efx); -extern void efx_stats_enable(struct efx_nic *efx); -extern void efx_reconfigure_port(struct efx_nic *efx); -extern void __efx_reconfigure_port(struct efx_nic *efx); +extern int efx_reconfigure_port(struct efx_nic *efx); +extern int __efx_reconfigure_port(struct efx_nic *efx); /* Ethtool support */ extern int efx_ethtool_get_settings(struct net_device *net_dev, @@ -74,10 +73,9 @@ extern int efx_ethtool_set_settings(struct net_device *net_dev, extern const struct ethtool_ops efx_ethtool_ops; /* Reset handling */ -extern void efx_reset_down(struct efx_nic *efx, enum reset_type method, - struct ethtool_cmd *ecmd); -extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, - struct ethtool_cmd *ecmd, bool ok); +extern int efx_reset(struct efx_nic *efx, enum reset_type method); +extern void efx_reset_down(struct efx_nic *efx, enum reset_type method); +extern int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok); /* Global */ extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); @@ -93,6 +91,7 @@ extern int efx_port_dummy_op_int(struct efx_nic *efx); extern void efx_port_dummy_op_void(struct efx_nic *efx); extern void efx_port_dummy_op_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); +extern bool efx_port_dummy_op_poll(struct efx_nic *efx); /* MTD */ #ifdef CONFIG_SFC_MTD @@ -116,4 +115,8 @@ static inline void efx_schedule_channel(struct efx_channel *channel) napi_schedule(&channel->napi_str); } +extern void efx_link_status_changed(struct efx_nic *efx); +extern void efx_link_set_advertising(struct efx_nic *efx, u32); +extern void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type); + #endif /* EFX_EFX_H */ diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h index fcd14b73f24..384cfe3b1be 100644 --- a/drivers/net/sfc/enum.h +++ b/drivers/net/sfc/enum.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2008 Solarflare Communications Inc. + * Copyright 2007-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -13,38 +13,101 @@ /** * enum efx_loopback_mode - loopback modes * @LOOPBACK_NONE: no loopback - * @LOOPBACK_GMAC: loopback within GMAC at unspecified level - * @LOOPBACK_XGMII: loopback within XMAC at XGMII level - * @LOOPBACK_XGXS: loopback within XMAC at XGXS level - * @LOOPBACK_XAUI: loopback within XMAC at XAUI level + * @LOOPBACK_DATA: data path loopback + * @LOOPBACK_GMAC: loopback within GMAC + * @LOOPBACK_XGMII: loopback after XMAC + * @LOOPBACK_XGXS: loopback within BPX after XGXS + * @LOOPBACK_XAUI: loopback within BPX before XAUI serdes + * @LOOPBACK_GMII: loopback within BPX after GMAC + * @LOOPBACK_SGMII: loopback within BPX within SGMII + * @LOOPBACK_XGBR: loopback within BPX within XGBR + * @LOOPBACK_XFI: loopback within BPX before XFI serdes + * @LOOPBACK_XAUI_FAR: loopback within BPX after XAUI serdes + * @LOOPBACK_GMII_FAR: loopback within BPX before SGMII + * @LOOPBACK_SGMII_FAR: loopback within BPX after SGMII + * @LOOPBACK_XFI_FAR: loopback after XFI serdes * @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level * @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level * @LOOPBACK_PCS: loopback within 10G PHY at PCS level * @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level - * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!) + * @LOOPBACK_XPORT: cross port loopback + * @LOOPBACK_XGMII_WS: wireside loopback excluding XMAC + * @LOOPBACK_XAUI_WS: wireside loopback within BPX within XAUI serdes + * @LOOPBACK_XAUI_WS_FAR: wireside loopback within BPX including XAUI serdes + * @LOOPBACK_XAUI_WS_NEAR: wireside loopback within BPX excluding XAUI serdes + * @LOOPBACK_GMII_WS: wireside loopback excluding GMAC + * @LOOPBACK_XFI_WS: wireside loopback excluding XFI serdes + * @LOOPBACK_XFI_WS_FAR: wireside loopback including XFI serdes + * @LOOPBACK_PHYXS_WS: wireside loopback within 10G PHY at PHYXS level */ -/* Please keep in order and up-to-date w.r.t the following two #defines */ +/* Please keep up-to-date w.r.t the following two #defines */ enum efx_loopback_mode { LOOPBACK_NONE = 0, - LOOPBACK_GMAC = 1, - LOOPBACK_XGMII = 2, - LOOPBACK_XGXS = 3, - LOOPBACK_XAUI = 4, - LOOPBACK_GPHY = 5, - LOOPBACK_PHYXS = 6, - LOOPBACK_PCS = 7, - LOOPBACK_PMAPMD = 8, - LOOPBACK_NETWORK = 9, + LOOPBACK_DATA = 1, + LOOPBACK_GMAC = 2, + LOOPBACK_XGMII = 3, + LOOPBACK_XGXS = 4, + LOOPBACK_XAUI = 5, + LOOPBACK_GMII = 6, + LOOPBACK_SGMII = 7, + LOOPBACK_XGBR = 8, + LOOPBACK_XFI = 9, + LOOPBACK_XAUI_FAR = 10, + LOOPBACK_GMII_FAR = 11, + LOOPBACK_SGMII_FAR = 12, + LOOPBACK_XFI_FAR = 13, + LOOPBACK_GPHY = 14, + LOOPBACK_PHYXS = 15, + LOOPBACK_PCS = 16, + LOOPBACK_PMAPMD = 17, + LOOPBACK_XPORT = 18, + LOOPBACK_XGMII_WS = 19, + LOOPBACK_XAUI_WS = 20, + LOOPBACK_XAUI_WS_FAR = 21, + LOOPBACK_XAUI_WS_NEAR = 22, + LOOPBACK_GMII_WS = 23, + LOOPBACK_XFI_WS = 24, + LOOPBACK_XFI_WS_FAR = 25, + LOOPBACK_PHYXS_WS = 26, LOOPBACK_MAX }; - #define LOOPBACK_TEST_MAX LOOPBACK_PMAPMD /* These loopbacks occur within the controller */ -#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_GMAC) | \ - (1 << LOOPBACK_XGMII)| \ - (1 << LOOPBACK_XGXS) | \ - (1 << LOOPBACK_XAUI)) +#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_DATA) | \ + (1 << LOOPBACK_GMAC) | \ + (1 << LOOPBACK_XGMII)| \ + (1 << LOOPBACK_XGXS) | \ + (1 << LOOPBACK_XAUI) | \ + (1 << LOOPBACK_GMII) | \ + (1 << LOOPBACK_SGMII) | \ + (1 << LOOPBACK_SGMII) | \ + (1 << LOOPBACK_XGBR) | \ + (1 << LOOPBACK_XFI) | \ + (1 << LOOPBACK_XAUI_FAR) | \ + (1 << LOOPBACK_GMII_FAR) | \ + (1 << LOOPBACK_SGMII_FAR) | \ + (1 << LOOPBACK_XFI_FAR) | \ + (1 << LOOPBACK_XGMII_WS) | \ + (1 << LOOPBACK_XAUI_WS) | \ + (1 << LOOPBACK_XAUI_WS_FAR) | \ + (1 << LOOPBACK_XAUI_WS_NEAR) | \ + (1 << LOOPBACK_GMII_WS) | \ + (1 << LOOPBACK_XFI_WS) | \ + (1 << LOOPBACK_XFI_WS_FAR)) + +#define LOOPBACKS_WS ((1 << LOOPBACK_XGMII_WS) | \ + (1 << LOOPBACK_XAUI_WS) | \ + (1 << LOOPBACK_XAUI_WS_FAR) | \ + (1 << LOOPBACK_XAUI_WS_NEAR) | \ + (1 << LOOPBACK_GMII_WS) | \ + (1 << LOOPBACK_XFI_WS) | \ + (1 << LOOPBACK_XFI_WS_FAR) | \ + (1 << LOOPBACK_PHYXS_WS)) + +#define LOOPBACKS_EXTERNAL(_efx) \ + ((_efx)->loopback_modes & ~LOOPBACKS_INTERNAL & \ + ~(1 << LOOPBACK_NONE)) #define LOOPBACK_MASK(_efx) \ (1 << (_efx)->loopback_mode) @@ -52,6 +115,9 @@ enum efx_loopback_mode { #define LOOPBACK_INTERNAL(_efx) \ (!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx))) +#define LOOPBACK_EXTERNAL(_efx) \ + (!!(LOOPBACK_MASK(_efx) & LOOPBACKS_EXTERNAL(_efx))) + #define LOOPBACK_CHANGED(_from, _to, _mask) \ (!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask))) @@ -78,6 +144,7 @@ enum efx_loopback_mode { * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch * @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors + * @RESET_TYPE_MC_FAILURE: MC reboot/assertion */ enum reset_type { RESET_TYPE_NONE = -1, @@ -92,6 +159,7 @@ enum reset_type { RESET_TYPE_RX_DESC_FETCH, RESET_TYPE_TX_DESC_FETCH, RESET_TYPE_TX_SKIP, + RESET_TYPE_MC_FAILURE, RESET_TYPE_MAX, }; diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index d8915b95e65..6c0bbed8c47 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -10,13 +10,12 @@ #include <linux/netdevice.h> #include <linux/ethtool.h> -#include <linux/mdio.h> #include <linux/rtnetlink.h> #include "net_driver.h" #include "workarounds.h" #include "selftest.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "spi.h" #include "mdio_10g.h" @@ -153,6 +152,7 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err), + EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_mcast_mismatch), EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc), }; @@ -174,14 +174,14 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) struct efx_nic *efx = netdev_priv(net_dev); do { - falcon_board(efx)->set_id_led(efx, EFX_LED_ON); + efx->type->set_id_led(efx, EFX_LED_ON); schedule_timeout_interruptible(HZ / 2); - falcon_board(efx)->set_id_led(efx, EFX_LED_OFF); + efx->type->set_id_led(efx, EFX_LED_OFF); schedule_timeout_interruptible(HZ / 2); } while (!signal_pending(current) && --count != 0); - falcon_board(efx)->set_id_led(efx, EFX_LED_DEFAULT); + efx->type->set_id_led(efx, EFX_LED_DEFAULT); return 0; } @@ -190,6 +190,7 @@ int efx_ethtool_get_settings(struct net_device *net_dev, struct ethtool_cmd *ecmd) { struct efx_nic *efx = netdev_priv(net_dev); + struct efx_link_state *link_state = &efx->link_state; mutex_lock(&efx->mac_lock); efx->phy_op->get_settings(efx, ecmd); @@ -197,6 +198,13 @@ int efx_ethtool_get_settings(struct net_device *net_dev, /* Falcon GMAC does not support 1000Mbps HD */ ecmd->supported &= ~SUPPORTED_1000baseT_Half; + /* Both MACs support pause frames (bidirectional and respond-only) */ + ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + + if (LOOPBACK_INTERNAL(efx)) { + ecmd->speed = link_state->speed; + ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; + } return 0; } @@ -218,9 +226,6 @@ int efx_ethtool_set_settings(struct net_device *net_dev, mutex_lock(&efx->mac_lock); rc = efx->phy_op->set_settings(efx, ecmd); mutex_unlock(&efx->mac_lock); - if (!rc) - efx_reconfigure_port(efx); - return rc; } @@ -231,6 +236,9 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev, strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver)); strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version)); + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) + siena_print_fwver(efx, info->fw_version, + sizeof(info->fw_version)); strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info)); } @@ -360,9 +368,21 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, efx_fill_test(n++, strings, data, &tests->registers, "core", 0, "registers", NULL); - for (i = 0; i < efx->phy_op->num_tests; i++) - efx_fill_test(n++, strings, data, &tests->phy[i], - "phy", 0, efx->phy_op->test_names[i], NULL); + if (efx->phy_op->run_tests != NULL) { + EFX_BUG_ON_PARANOID(efx->phy_op->test_name == NULL); + + for (i = 0; true; ++i) { + const char *name; + + EFX_BUG_ON_PARANOID(i >= EFX_MAX_PHY_TESTS); + name = efx->phy_op->test_name(efx, i); + if (name == NULL) + break; + + efx_fill_test(n++, strings, data, &tests->phy[i], + "phy", 0, name, NULL); + } + } /* Loopback tests */ for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { @@ -451,6 +471,36 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, } } +static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable) +{ + struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev); + unsigned long features; + + features = NETIF_F_TSO; + if (efx->type->offload_features & NETIF_F_V6_CSUM) + features |= NETIF_F_TSO6; + + if (enable) + net_dev->features |= features; + else + net_dev->features &= ~features; + + return 0; +} + +static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable) +{ + struct efx_nic *efx = netdev_priv(net_dev); + unsigned long features = efx->type->offload_features & NETIF_F_ALL_CSUM; + + if (enable) + net_dev->features |= features; + else + net_dev->features &= ~features; + + return 0; +} + static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable) { struct efx_nic *efx = netdev_priv(net_dev); @@ -550,7 +600,8 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev, rc = mutex_lock_interruptible(&efx->spi_lock); if (rc) return rc; - rc = falcon_spi_read(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, + rc = falcon_spi_read(efx, spi, + eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, eeprom->len, &len, buf); mutex_unlock(&efx->spi_lock); @@ -573,7 +624,8 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev, rc = mutex_lock_interruptible(&efx->spi_lock); if (rc) return rc; - rc = falcon_spi_write(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, + rc = falcon_spi_write(efx, spi, + eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, eeprom->len, &len, buf); mutex_unlock(&efx->spi_lock); @@ -606,8 +658,8 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev, coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive; coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation; - coalesce->tx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION; - coalesce->rx_coalesce_usecs_irq *= FALCON_IRQ_MOD_RESOLUTION; + coalesce->tx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION; + coalesce->rx_coalesce_usecs_irq *= EFX_IRQ_MOD_RESOLUTION; return 0; } @@ -648,7 +700,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev, efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive); efx_for_each_channel(channel, efx) - falcon_set_int_moderation(channel); + efx->type->push_irq_moderation(channel); return 0; } @@ -657,8 +709,12 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { struct efx_nic *efx = netdev_priv(net_dev); - enum efx_fc_type wanted_fc; + enum efx_fc_type wanted_fc, old_fc; + u32 old_adv; bool reset; + int rc = 0; + + mutex_lock(&efx->mac_lock); wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | (pause->tx_pause ? EFX_FC_TX : 0) | @@ -666,14 +722,14 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n"); - return -EINVAL; + rc = -EINVAL; + goto out; } - if (!(efx->phy_op->mmds & MDIO_DEVS_AN) && - (wanted_fc & EFX_FC_AUTO)) { - EFX_LOG(efx, "PHY does not support flow control " - "autonegotiation\n"); - return -EINVAL; + if ((wanted_fc & EFX_FC_AUTO) && !efx->link_advertising) { + EFX_LOG(efx, "Autonegotiation is disabled\n"); + rc = -EINVAL; + goto out; } /* TX flow control may automatically turn itself off if the @@ -683,27 +739,40 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, * and fix it be cycling transmit flow control on this end. */ reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX); if (EFX_WORKAROUND_11482(efx) && reset) { - if (falcon_rev(efx) >= FALCON_REV_B0) { + if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { /* Recover by resetting the EM block */ - if (efx->link_state.up) - falcon_drain_tx_fifo(efx); + falcon_stop_nic_stats(efx); + falcon_drain_tx_fifo(efx); + efx->mac_op->reconfigure(efx); + falcon_start_nic_stats(efx); } else { /* Schedule a reset to recover */ efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); } } - /* Try to push the pause parameters */ - mutex_lock(&efx->mac_lock); + old_adv = efx->link_advertising; + old_fc = efx->wanted_fc; + efx_link_set_wanted_fc(efx, wanted_fc); + if (efx->link_advertising != old_adv || + (efx->wanted_fc ^ old_fc) & EFX_FC_AUTO) { + rc = efx->phy_op->reconfigure(efx); + if (rc) { + EFX_ERR(efx, "Unable to advertise requested flow " + "control setting\n"); + goto out; + } + } - efx->wanted_fc = wanted_fc; - if (efx->phy_op->mmds & MDIO_DEVS_AN) - mdio45_ethtool_spauseparam_an(&efx->mdio, pause); - __efx_reconfigure_port(efx); + /* Reconfigure the MAC. The PHY *may* generate a link state change event + * if the user just changed the advertised capabilities, but there's no + * harm doing this twice */ + efx->mac_op->reconfigure(efx); +out: mutex_unlock(&efx->mac_lock); - return 0; + return rc; } static void efx_ethtool_get_pauseparam(struct net_device *net_dev, @@ -717,6 +786,50 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, } +static void efx_ethtool_get_wol(struct net_device *net_dev, + struct ethtool_wolinfo *wol) +{ + struct efx_nic *efx = netdev_priv(net_dev); + return efx->type->get_wol(efx, wol); +} + + +static int efx_ethtool_set_wol(struct net_device *net_dev, + struct ethtool_wolinfo *wol) +{ + struct efx_nic *efx = netdev_priv(net_dev); + return efx->type->set_wol(efx, wol->wolopts); +} + +extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) +{ + struct efx_nic *efx = netdev_priv(net_dev); + enum reset_type method; + enum { + ETH_RESET_EFX_INVISIBLE = (ETH_RESET_DMA | ETH_RESET_FILTER | + ETH_RESET_OFFLOAD | ETH_RESET_MAC) + }; + + /* Check for minimal reset flags */ + if ((*flags & ETH_RESET_EFX_INVISIBLE) != ETH_RESET_EFX_INVISIBLE) + return -EINVAL; + *flags ^= ETH_RESET_EFX_INVISIBLE; + method = RESET_TYPE_INVISIBLE; + + if (*flags & ETH_RESET_PHY) { + *flags ^= ETH_RESET_PHY; + method = RESET_TYPE_ALL; + } + + if ((*flags & efx->type->reset_world_flags) == + efx->type->reset_world_flags) { + *flags ^= efx->type->reset_world_flags; + method = RESET_TYPE_WORLD; + } + + return efx_reset(efx, method); +} + const struct ethtool_ops efx_ethtool_ops = { .get_settings = efx_ethtool_get_settings, .set_settings = efx_ethtool_set_settings, @@ -733,11 +846,13 @@ const struct ethtool_ops efx_ethtool_ops = { .get_rx_csum = efx_ethtool_get_rx_csum, .set_rx_csum = efx_ethtool_set_rx_csum, .get_tx_csum = ethtool_op_get_tx_csum, - .set_tx_csum = ethtool_op_set_tx_csum, + /* Need to enable/disable IPv6 too */ + .set_tx_csum = efx_ethtool_set_tx_csum, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, - .set_tso = ethtool_op_set_tso, + /* Need to enable/disable TSO-IPv6 too */ + .set_tso = efx_ethtool_set_tso, .get_flags = ethtool_op_get_flags, .set_flags = ethtool_op_set_flags, .get_sset_count = efx_ethtool_get_sset_count, @@ -745,4 +860,7 @@ const struct ethtool_ops efx_ethtool_ops = { .get_strings = efx_ethtool_get_strings, .phys_id = efx_ethtool_phys_id, .get_ethtool_stats = efx_ethtool_get_stats, + .get_wol = efx_ethtool_get_wol, + .set_wol = efx_ethtool_set_wol, + .reset = efx_ethtool_reset, }; diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 41a321b0e8c..17afcd26e87 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -20,41 +20,14 @@ #include "efx.h" #include "mac.h" #include "spi.h" -#include "falcon.h" +#include "nic.h" #include "regs.h" #include "io.h" #include "mdio_10g.h" #include "phy.h" #include "workarounds.h" -/* Falcon hardware control. - * Falcon is the internal codename for the SFC4000 controller that is - * present in SFE400X evaluation boards - */ - -/************************************************************************** - * - * Configurable values - * - ************************************************************************** - */ - -static int disable_dma_stats; - -/* This is set to 16 for a good reason. In summary, if larger than - * 16, the descriptor cache holds more than a default socket - * buffer's worth of packets (for UDP we can only have at most one - * socket buffer's worth outstanding). This combined with the fact - * that we only get 1 TX event per descriptor cache means the NIC - * goes idle. - */ -#define TX_DC_ENTRIES 16 -#define TX_DC_ENTRIES_ORDER 0 -#define TX_DC_BASE 0x130000 - -#define RX_DC_ENTRIES 64 -#define RX_DC_ENTRIES_ORDER 2 -#define RX_DC_BASE 0x100000 +/* Hardware control for SFC4000 (aka Falcon). */ static const unsigned int /* "Large" EEPROM device: Atmel AT25640 or similar @@ -70,90 +43,6 @@ default_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN) | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN) | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)); -/* RX FIFO XOFF watermark - * - * When the amount of the RX FIFO increases used increases past this - * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A) - * This also has an effect on RX/TX arbitration - */ -static int rx_xoff_thresh_bytes = -1; -module_param(rx_xoff_thresh_bytes, int, 0644); -MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold"); - -/* RX FIFO XON watermark - * - * When the amount of the RX FIFO used decreases below this - * watermark send XON. Only used if TX flow control is enabled (ethtool -A) - * This also has an effect on RX/TX arbitration - */ -static int rx_xon_thresh_bytes = -1; -module_param(rx_xon_thresh_bytes, int, 0644); -MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); - -/* If FALCON_MAX_INT_ERRORS internal errors occur within - * FALCON_INT_ERROR_EXPIRE seconds, we consider the NIC broken and - * disable it. - */ -#define FALCON_INT_ERROR_EXPIRE 3600 -#define FALCON_MAX_INT_ERRORS 5 - -/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times - */ -#define FALCON_FLUSH_INTERVAL 10 -#define FALCON_FLUSH_POLL_COUNT 100 - -/************************************************************************** - * - * Falcon constants - * - ************************************************************************** - */ - -/* Size and alignment of special buffers (4KB) */ -#define FALCON_BUF_SIZE 4096 - -/* Dummy SRAM size code */ -#define SRM_NB_BSZ_ONCHIP_ONLY (-1) - -#define FALCON_IS_DUAL_FUNC(efx) \ - (falcon_rev(efx) < FALCON_REV_B0) - -/************************************************************************** - * - * Falcon hardware access - * - **************************************************************************/ - -static inline void falcon_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, - unsigned int index) -{ - efx_sram_writeq(efx, efx->membase + efx->type->buf_tbl_base, - value, index); -} - -/* Read the current event from the event queue */ -static inline efx_qword_t *falcon_event(struct efx_channel *channel, - unsigned int index) -{ - return (((efx_qword_t *) (channel->eventq.addr)) + index); -} - -/* See if an event is present - * - * We check both the high and low dword of the event for all ones. We - * wrote all ones when we cleared the event, and no valid event can - * have all ones in either its high or low dwords. This approach is - * robust against reordering. - * - * Note that using a single 64-bit comparison is incorrect; even - * though the CPU read will be atomic, the DMA write may not be. - */ -static inline int falcon_event_present(efx_qword_t *event) -{ - return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) | - EFX_DWORD_IS_ALL_ONES(event->dword[1]))); -} - /************************************************************************** * * I2C bus - this is a bit-bashing interface using GPIO pins @@ -210,843 +99,7 @@ static struct i2c_algo_bit_data falcon_i2c_bit_operations = { .timeout = DIV_ROUND_UP(HZ, 20), }; -/************************************************************************** - * - * Falcon special buffer handling - * Special buffers are used for event queues and the TX and RX - * descriptor rings. - * - *************************************************************************/ - -/* - * Initialise a Falcon special buffer - * - * This will define a buffer (previously allocated via - * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing - * it to be used for event queues, descriptor rings etc. - */ -static void -falcon_init_special_buffer(struct efx_nic *efx, - struct efx_special_buffer *buffer) -{ - efx_qword_t buf_desc; - int index; - dma_addr_t dma_addr; - int i; - - EFX_BUG_ON_PARANOID(!buffer->addr); - - /* Write buffer descriptors to NIC */ - for (i = 0; i < buffer->entries; i++) { - index = buffer->index + i; - dma_addr = buffer->dma_addr + (i * 4096); - EFX_LOG(efx, "mapping special buffer %d at %llx\n", - index, (unsigned long long)dma_addr); - EFX_POPULATE_QWORD_3(buf_desc, - FRF_AZ_BUF_ADR_REGION, 0, - FRF_AZ_BUF_ADR_FBUF, dma_addr >> 12, - FRF_AZ_BUF_OWNER_ID_FBUF, 0); - falcon_write_buf_tbl(efx, &buf_desc, index); - } -} - -/* Unmaps a buffer from Falcon and clears the buffer table entries */ -static void -falcon_fini_special_buffer(struct efx_nic *efx, - struct efx_special_buffer *buffer) -{ - efx_oword_t buf_tbl_upd; - unsigned int start = buffer->index; - unsigned int end = (buffer->index + buffer->entries - 1); - - if (!buffer->entries) - return; - - EFX_LOG(efx, "unmapping special buffers %d-%d\n", - buffer->index, buffer->index + buffer->entries - 1); - - EFX_POPULATE_OWORD_4(buf_tbl_upd, - FRF_AZ_BUF_UPD_CMD, 0, - FRF_AZ_BUF_CLR_CMD, 1, - FRF_AZ_BUF_CLR_END_ID, end, - FRF_AZ_BUF_CLR_START_ID, start); - efx_writeo(efx, &buf_tbl_upd, FR_AZ_BUF_TBL_UPD); -} - -/* - * Allocate a new Falcon special buffer - * - * This allocates memory for a new buffer, clears it and allocates a - * new buffer ID range. It does not write into Falcon's buffer table. - * - * This call will allocate 4KB buffers, since Falcon can't use 8KB - * buffers for event queues and descriptor rings. - */ -static int falcon_alloc_special_buffer(struct efx_nic *efx, - struct efx_special_buffer *buffer, - unsigned int len) -{ - len = ALIGN(len, FALCON_BUF_SIZE); - - buffer->addr = pci_alloc_consistent(efx->pci_dev, len, - &buffer->dma_addr); - if (!buffer->addr) - return -ENOMEM; - buffer->len = len; - buffer->entries = len / FALCON_BUF_SIZE; - BUG_ON(buffer->dma_addr & (FALCON_BUF_SIZE - 1)); - - /* All zeros is a potentially valid event so memset to 0xff */ - memset(buffer->addr, 0xff, len); - - /* Select new buffer ID */ - buffer->index = efx->next_buffer_table; - efx->next_buffer_table += buffer->entries; - - EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x " - "(virt %p phys %llx)\n", buffer->index, - buffer->index + buffer->entries - 1, - (u64)buffer->dma_addr, len, - buffer->addr, (u64)virt_to_phys(buffer->addr)); - - return 0; -} - -static void falcon_free_special_buffer(struct efx_nic *efx, - struct efx_special_buffer *buffer) -{ - if (!buffer->addr) - return; - - EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x " - "(virt %p phys %llx)\n", buffer->index, - buffer->index + buffer->entries - 1, - (u64)buffer->dma_addr, buffer->len, - buffer->addr, (u64)virt_to_phys(buffer->addr)); - - pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr, - buffer->dma_addr); - buffer->addr = NULL; - buffer->entries = 0; -} - -/************************************************************************** - * - * Falcon generic buffer handling - * These buffers are used for interrupt status and MAC stats - * - **************************************************************************/ - -static int falcon_alloc_buffer(struct efx_nic *efx, - struct efx_buffer *buffer, unsigned int len) -{ - buffer->addr = pci_alloc_consistent(efx->pci_dev, len, - &buffer->dma_addr); - if (!buffer->addr) - return -ENOMEM; - buffer->len = len; - memset(buffer->addr, 0, len); - return 0; -} - -static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) -{ - if (buffer->addr) { - pci_free_consistent(efx->pci_dev, buffer->len, - buffer->addr, buffer->dma_addr); - buffer->addr = NULL; - } -} - -/************************************************************************** - * - * Falcon TX path - * - **************************************************************************/ - -/* Returns a pointer to the specified transmit descriptor in the TX - * descriptor queue belonging to the specified channel. - */ -static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue, - unsigned int index) -{ - return (((efx_qword_t *) (tx_queue->txd.addr)) + index); -} - -/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */ -static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue) -{ - unsigned write_ptr; - efx_dword_t reg; - - write_ptr = tx_queue->write_count & EFX_TXQ_MASK; - EFX_POPULATE_DWORD_1(reg, FRF_AZ_TX_DESC_WPTR_DWORD, write_ptr); - efx_writed_page(tx_queue->efx, ®, - FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue); -} - - -/* For each entry inserted into the software descriptor ring, create a - * descriptor in the hardware TX descriptor ring (in host memory), and - * write a doorbell. - */ -void falcon_push_buffers(struct efx_tx_queue *tx_queue) -{ - - struct efx_tx_buffer *buffer; - efx_qword_t *txd; - unsigned write_ptr; - - BUG_ON(tx_queue->write_count == tx_queue->insert_count); - - do { - write_ptr = tx_queue->write_count & EFX_TXQ_MASK; - buffer = &tx_queue->buffer[write_ptr]; - txd = falcon_tx_desc(tx_queue, write_ptr); - ++tx_queue->write_count; - - /* Create TX descriptor ring entry */ - EFX_POPULATE_QWORD_4(*txd, - FSF_AZ_TX_KER_CONT, buffer->continuation, - FSF_AZ_TX_KER_BYTE_COUNT, buffer->len, - FSF_AZ_TX_KER_BUF_REGION, 0, - FSF_AZ_TX_KER_BUF_ADDR, buffer->dma_addr); - } while (tx_queue->write_count != tx_queue->insert_count); - - wmb(); /* Ensure descriptors are written before they are fetched */ - falcon_notify_tx_desc(tx_queue); -} - -/* Allocate hardware resources for a TX queue */ -int falcon_probe_tx(struct efx_tx_queue *tx_queue) -{ - struct efx_nic *efx = tx_queue->efx; - BUILD_BUG_ON(EFX_TXQ_SIZE < 512 || EFX_TXQ_SIZE > 4096 || - EFX_TXQ_SIZE & EFX_TXQ_MASK); - return falcon_alloc_special_buffer(efx, &tx_queue->txd, - EFX_TXQ_SIZE * sizeof(efx_qword_t)); -} - -void falcon_init_tx(struct efx_tx_queue *tx_queue) -{ - efx_oword_t tx_desc_ptr; - struct efx_nic *efx = tx_queue->efx; - - tx_queue->flushed = false; - - /* Pin TX descriptor ring */ - falcon_init_special_buffer(efx, &tx_queue->txd); - - /* Push TX descriptor ring to card */ - EFX_POPULATE_OWORD_10(tx_desc_ptr, - FRF_AZ_TX_DESCQ_EN, 1, - FRF_AZ_TX_ISCSI_DDIG_EN, 0, - FRF_AZ_TX_ISCSI_HDIG_EN, 0, - FRF_AZ_TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index, - FRF_AZ_TX_DESCQ_EVQ_ID, - tx_queue->channel->channel, - FRF_AZ_TX_DESCQ_OWNER_ID, 0, - FRF_AZ_TX_DESCQ_LABEL, tx_queue->queue, - FRF_AZ_TX_DESCQ_SIZE, - __ffs(tx_queue->txd.entries), - FRF_AZ_TX_DESCQ_TYPE, 0, - FRF_BZ_TX_NON_IP_DROP_DIS, 1); - - if (falcon_rev(efx) >= FALCON_REV_B0) { - int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM; - EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum); - EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS, - !csum); - } - - efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, - tx_queue->queue); - - if (falcon_rev(efx) < FALCON_REV_B0) { - efx_oword_t reg; - - /* Only 128 bits in this register */ - BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128); - - efx_reado(efx, ®, FR_AA_TX_CHKSM_CFG); - if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM) - clear_bit_le(tx_queue->queue, (void *)®); - else - set_bit_le(tx_queue->queue, (void *)®); - efx_writeo(efx, ®, FR_AA_TX_CHKSM_CFG); - } -} - -static void falcon_flush_tx_queue(struct efx_tx_queue *tx_queue) -{ - struct efx_nic *efx = tx_queue->efx; - efx_oword_t tx_flush_descq; - - /* Post a flush command */ - EFX_POPULATE_OWORD_2(tx_flush_descq, - FRF_AZ_TX_FLUSH_DESCQ_CMD, 1, - FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue); - efx_writeo(efx, &tx_flush_descq, FR_AZ_TX_FLUSH_DESCQ); -} - -void falcon_fini_tx(struct efx_tx_queue *tx_queue) -{ - struct efx_nic *efx = tx_queue->efx; - efx_oword_t tx_desc_ptr; - - /* The queue should have been flushed */ - WARN_ON(!tx_queue->flushed); - - /* Remove TX descriptor ring from card */ - EFX_ZERO_OWORD(tx_desc_ptr); - efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, - tx_queue->queue); - - /* Unpin TX descriptor ring */ - falcon_fini_special_buffer(efx, &tx_queue->txd); -} - -/* Free buffers backing TX queue */ -void falcon_remove_tx(struct efx_tx_queue *tx_queue) -{ - falcon_free_special_buffer(tx_queue->efx, &tx_queue->txd); -} - -/************************************************************************** - * - * Falcon RX path - * - **************************************************************************/ - -/* Returns a pointer to the specified descriptor in the RX descriptor queue */ -static inline efx_qword_t *falcon_rx_desc(struct efx_rx_queue *rx_queue, - unsigned int index) -{ - return (((efx_qword_t *) (rx_queue->rxd.addr)) + index); -} - -/* This creates an entry in the RX descriptor queue */ -static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue, - unsigned index) -{ - struct efx_rx_buffer *rx_buf; - efx_qword_t *rxd; - - rxd = falcon_rx_desc(rx_queue, index); - rx_buf = efx_rx_buffer(rx_queue, index); - EFX_POPULATE_QWORD_3(*rxd, - FSF_AZ_RX_KER_BUF_SIZE, - rx_buf->len - - rx_queue->efx->type->rx_buffer_padding, - FSF_AZ_RX_KER_BUF_REGION, 0, - FSF_AZ_RX_KER_BUF_ADDR, rx_buf->dma_addr); -} - -/* This writes to the RX_DESC_WPTR register for the specified receive - * descriptor ring. - */ -void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue) -{ - efx_dword_t reg; - unsigned write_ptr; - - while (rx_queue->notified_count != rx_queue->added_count) { - falcon_build_rx_desc(rx_queue, - rx_queue->notified_count & - EFX_RXQ_MASK); - ++rx_queue->notified_count; - } - - wmb(); - write_ptr = rx_queue->added_count & EFX_RXQ_MASK; - EFX_POPULATE_DWORD_1(reg, FRF_AZ_RX_DESC_WPTR_DWORD, write_ptr); - efx_writed_page(rx_queue->efx, ®, - FR_AZ_RX_DESC_UPD_DWORD_P0, rx_queue->queue); -} - -int falcon_probe_rx(struct efx_rx_queue *rx_queue) -{ - struct efx_nic *efx = rx_queue->efx; - BUILD_BUG_ON(EFX_RXQ_SIZE < 512 || EFX_RXQ_SIZE > 4096 || - EFX_RXQ_SIZE & EFX_RXQ_MASK); - return falcon_alloc_special_buffer(efx, &rx_queue->rxd, - EFX_RXQ_SIZE * sizeof(efx_qword_t)); -} - -void falcon_init_rx(struct efx_rx_queue *rx_queue) -{ - efx_oword_t rx_desc_ptr; - struct efx_nic *efx = rx_queue->efx; - bool is_b0 = falcon_rev(efx) >= FALCON_REV_B0; - bool iscsi_digest_en = is_b0; - - EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n", - rx_queue->queue, rx_queue->rxd.index, - rx_queue->rxd.index + rx_queue->rxd.entries - 1); - - rx_queue->flushed = false; - - /* Pin RX descriptor ring */ - falcon_init_special_buffer(efx, &rx_queue->rxd); - - /* Push RX descriptor ring to card */ - EFX_POPULATE_OWORD_10(rx_desc_ptr, - FRF_AZ_RX_ISCSI_DDIG_EN, iscsi_digest_en, - FRF_AZ_RX_ISCSI_HDIG_EN, iscsi_digest_en, - FRF_AZ_RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index, - FRF_AZ_RX_DESCQ_EVQ_ID, - rx_queue->channel->channel, - FRF_AZ_RX_DESCQ_OWNER_ID, 0, - FRF_AZ_RX_DESCQ_LABEL, rx_queue->queue, - FRF_AZ_RX_DESCQ_SIZE, - __ffs(rx_queue->rxd.entries), - FRF_AZ_RX_DESCQ_TYPE, 0 /* kernel queue */ , - /* For >=B0 this is scatter so disable */ - FRF_AZ_RX_DESCQ_JUMBO, !is_b0, - FRF_AZ_RX_DESCQ_EN, 1); - efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, - rx_queue->queue); -} - -static void falcon_flush_rx_queue(struct efx_rx_queue *rx_queue) -{ - struct efx_nic *efx = rx_queue->efx; - efx_oword_t rx_flush_descq; - - /* Post a flush command */ - EFX_POPULATE_OWORD_2(rx_flush_descq, - FRF_AZ_RX_FLUSH_DESCQ_CMD, 1, - FRF_AZ_RX_FLUSH_DESCQ, rx_queue->queue); - efx_writeo(efx, &rx_flush_descq, FR_AZ_RX_FLUSH_DESCQ); -} - -void falcon_fini_rx(struct efx_rx_queue *rx_queue) -{ - efx_oword_t rx_desc_ptr; - struct efx_nic *efx = rx_queue->efx; - - /* The queue should already have been flushed */ - WARN_ON(!rx_queue->flushed); - - /* Remove RX descriptor ring from card */ - EFX_ZERO_OWORD(rx_desc_ptr); - efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, - rx_queue->queue); - - /* Unpin RX descriptor ring */ - falcon_fini_special_buffer(efx, &rx_queue->rxd); -} - -/* Free buffers backing RX queue */ -void falcon_remove_rx(struct efx_rx_queue *rx_queue) -{ - falcon_free_special_buffer(rx_queue->efx, &rx_queue->rxd); -} - -/************************************************************************** - * - * Falcon event queue processing - * Event queues are processed by per-channel tasklets. - * - **************************************************************************/ - -/* Update a channel's event queue's read pointer (RPTR) register - * - * This writes the EVQ_RPTR_REG register for the specified channel's - * event queue. - * - * Note that EVQ_RPTR_REG contains the index of the "last read" event, - * whereas channel->eventq_read_ptr contains the index of the "next to - * read" event. - */ -void falcon_eventq_read_ack(struct efx_channel *channel) -{ - efx_dword_t reg; - struct efx_nic *efx = channel->efx; - - EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr); - efx_writed_table(efx, ®, efx->type->evq_rptr_tbl_base, - channel->channel); -} - -/* Use HW to insert a SW defined event */ -void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event) -{ - efx_oword_t drv_ev_reg; - - BUILD_BUG_ON(FRF_AZ_DRV_EV_DATA_LBN != 0 || - FRF_AZ_DRV_EV_DATA_WIDTH != 64); - drv_ev_reg.u32[0] = event->u32[0]; - drv_ev_reg.u32[1] = event->u32[1]; - drv_ev_reg.u32[2] = 0; - drv_ev_reg.u32[3] = 0; - EFX_SET_OWORD_FIELD(drv_ev_reg, FRF_AZ_DRV_EV_QID, channel->channel); - efx_writeo(channel->efx, &drv_ev_reg, FR_AZ_DRV_EV); -} - -/* Handle a transmit completion event - * - * Falcon batches TX completion events; the message we receive is of - * the form "complete all TX events up to this index". - */ -static void falcon_handle_tx_event(struct efx_channel *channel, - efx_qword_t *event) -{ - unsigned int tx_ev_desc_ptr; - unsigned int tx_ev_q_label; - struct efx_tx_queue *tx_queue; - struct efx_nic *efx = channel->efx; - - if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) { - /* Transmit completion */ - tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR); - tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); - tx_queue = &efx->tx_queue[tx_ev_q_label]; - channel->irq_mod_score += - (tx_ev_desc_ptr - tx_queue->read_count) & - EFX_TXQ_MASK; - efx_xmit_done(tx_queue, tx_ev_desc_ptr); - } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) { - /* Rewrite the FIFO write pointer */ - tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); - tx_queue = &efx->tx_queue[tx_ev_q_label]; - - if (efx_dev_registered(efx)) - netif_tx_lock(efx->net_dev); - falcon_notify_tx_desc(tx_queue); - if (efx_dev_registered(efx)) - netif_tx_unlock(efx->net_dev); - } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR) && - EFX_WORKAROUND_10727(efx)) { - efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); - } else { - EFX_ERR(efx, "channel %d unexpected TX event " - EFX_QWORD_FMT"\n", channel->channel, - EFX_QWORD_VAL(*event)); - } -} - -/* Detect errors included in the rx_evt_pkt_ok bit. */ -static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, - const efx_qword_t *event, - bool *rx_ev_pkt_ok, - bool *discard) -{ - struct efx_nic *efx = rx_queue->efx; - bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err; - bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err; - bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc; - bool rx_ev_other_err, rx_ev_pause_frm; - bool rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt; - unsigned rx_ev_pkt_type; - - rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE); - rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT); - rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_TOBE_DISC); - rx_ev_pkt_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_TYPE); - rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event, - FSF_AZ_RX_EV_BUF_OWNER_ID_ERR); - rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_IP_FRAG_ERR); - rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event, - FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR); - rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event, - FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR); - rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_ETH_CRC_ERR); - rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_FRM_TRUNC); - rx_ev_drib_nib = ((falcon_rev(efx) >= FALCON_REV_B0) ? - 0 : EFX_QWORD_FIELD(*event, FSF_AA_RX_EV_DRIB_NIB)); - rx_ev_pause_frm = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PAUSE_FRM_ERR); - - /* Every error apart from tobe_disc and pause_frm */ - rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err | - rx_ev_buf_owner_id_err | rx_ev_eth_crc_err | - rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err); - - /* Count errors that are not in MAC stats. Ignore expected - * checksum errors during self-test. */ - if (rx_ev_frm_trunc) - ++rx_queue->channel->n_rx_frm_trunc; - else if (rx_ev_tobe_disc) - ++rx_queue->channel->n_rx_tobe_disc; - else if (!efx->loopback_selftest) { - if (rx_ev_ip_hdr_chksum_err) - ++rx_queue->channel->n_rx_ip_hdr_chksum_err; - else if (rx_ev_tcp_udp_chksum_err) - ++rx_queue->channel->n_rx_tcp_udp_chksum_err; - } - if (rx_ev_ip_frag_err) - ++rx_queue->channel->n_rx_ip_frag_err; - - /* The frame must be discarded if any of these are true. */ - *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib | - rx_ev_tobe_disc | rx_ev_pause_frm); - - /* TOBE_DISC is expected on unicast mismatches; don't print out an - * error message. FRM_TRUNC indicates RXDP dropped the packet due - * to a FIFO overflow. - */ -#ifdef EFX_ENABLE_DEBUG - if (rx_ev_other_err) { - EFX_INFO_RL(efx, " RX queue %d unexpected RX event " - EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n", - rx_queue->queue, EFX_QWORD_VAL(*event), - rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "", - rx_ev_ip_hdr_chksum_err ? - " [IP_HDR_CHKSUM_ERR]" : "", - rx_ev_tcp_udp_chksum_err ? - " [TCP_UDP_CHKSUM_ERR]" : "", - rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "", - rx_ev_frm_trunc ? " [FRM_TRUNC]" : "", - rx_ev_drib_nib ? " [DRIB_NIB]" : "", - rx_ev_tobe_disc ? " [TOBE_DISC]" : "", - rx_ev_pause_frm ? " [PAUSE]" : ""); - } -#endif -} - -/* Handle receive events that are not in-order. */ -static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue, - unsigned index) -{ - struct efx_nic *efx = rx_queue->efx; - unsigned expected, dropped; - - expected = rx_queue->removed_count & EFX_RXQ_MASK; - dropped = (index - expected) & EFX_RXQ_MASK; - EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n", - dropped, index, expected); - - efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ? - RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); -} - -/* Handle a packet received event - * - * Falcon silicon gives a "discard" flag if it's a unicast packet with the - * wrong destination address - * Also "is multicast" and "matches multicast filter" flags can be used to - * discard non-matching multicast packets. - */ -static void falcon_handle_rx_event(struct efx_channel *channel, - const efx_qword_t *event) -{ - unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt; - unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt; - unsigned expected_ptr; - bool rx_ev_pkt_ok, discard = false, checksummed; - struct efx_rx_queue *rx_queue; - struct efx_nic *efx = channel->efx; - - /* Basic packet information */ - rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT); - rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_OK); - rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE); - WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_JUMBO_CONT)); - WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_SOP) != 1); - WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_Q_LABEL) != - channel->channel); - - rx_queue = &efx->rx_queue[channel->channel]; - - rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR); - expected_ptr = rx_queue->removed_count & EFX_RXQ_MASK; - if (unlikely(rx_ev_desc_ptr != expected_ptr)) - falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); - - if (likely(rx_ev_pkt_ok)) { - /* If packet is marked as OK and packet type is TCP/IPv4 or - * UDP/IPv4, then we can rely on the hardware checksum. - */ - checksummed = - efx->rx_checksum_enabled && - (rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP || - rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP); - } else { - falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, - &discard); - checksummed = false; - } - - /* Detect multicast packets that didn't match the filter */ - rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT); - if (rx_ev_mcast_pkt) { - unsigned int rx_ev_mcast_hash_match = - EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_HASH_MATCH); - - if (unlikely(!rx_ev_mcast_hash_match)) - discard = true; - } - - channel->irq_mod_score += 2; - - /* Handle received packet */ - efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, - checksummed, discard); -} - -/* Global events are basically PHY events */ -static void falcon_handle_global_event(struct efx_channel *channel, - efx_qword_t *event) -{ - struct efx_nic *efx = channel->efx; - bool handled = false; - - if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) || - EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) || - EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) { - efx->phy_op->clear_interrupt(efx); - queue_work(efx->workqueue, &efx->phy_work); - handled = true; - } - - if ((falcon_rev(efx) >= FALCON_REV_B0) && - EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) { - queue_work(efx->workqueue, &efx->mac_work); - handled = true; - } - - if (falcon_rev(efx) <= FALCON_REV_A1 ? - EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) : - EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) { - EFX_ERR(efx, "channel %d seen global RX_RESET " - "event. Resetting.\n", channel->channel); - - atomic_inc(&efx->rx_reset); - efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ? - RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); - handled = true; - } - - if (!handled) - EFX_ERR(efx, "channel %d unknown global event " - EFX_QWORD_FMT "\n", channel->channel, - EFX_QWORD_VAL(*event)); -} - -static void falcon_handle_driver_event(struct efx_channel *channel, - efx_qword_t *event) -{ - struct efx_nic *efx = channel->efx; - unsigned int ev_sub_code; - unsigned int ev_sub_data; - - ev_sub_code = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBCODE); - ev_sub_data = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA); - - switch (ev_sub_code) { - case FSE_AZ_TX_DESCQ_FLS_DONE_EV: - EFX_TRACE(efx, "channel %d TXQ %d flushed\n", - channel->channel, ev_sub_data); - break; - case FSE_AZ_RX_DESCQ_FLS_DONE_EV: - EFX_TRACE(efx, "channel %d RXQ %d flushed\n", - channel->channel, ev_sub_data); - break; - case FSE_AZ_EVQ_INIT_DONE_EV: - EFX_LOG(efx, "channel %d EVQ %d initialised\n", - channel->channel, ev_sub_data); - break; - case FSE_AZ_SRM_UPD_DONE_EV: - EFX_TRACE(efx, "channel %d SRAM update done\n", - channel->channel); - break; - case FSE_AZ_WAKE_UP_EV: - EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n", - channel->channel, ev_sub_data); - break; - case FSE_AZ_TIMER_EV: - EFX_TRACE(efx, "channel %d RX queue %d timer expired\n", - channel->channel, ev_sub_data); - break; - case FSE_AA_RX_RECOVER_EV: - EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. " - "Resetting.\n", channel->channel); - atomic_inc(&efx->rx_reset); - efx_schedule_reset(efx, - EFX_WORKAROUND_6555(efx) ? - RESET_TYPE_RX_RECOVERY : - RESET_TYPE_DISABLE); - break; - case FSE_BZ_RX_DSC_ERROR_EV: - EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error." - " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data); - efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH); - break; - case FSE_BZ_TX_DSC_ERROR_EV: - EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error." - " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data); - efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); - break; - default: - EFX_TRACE(efx, "channel %d unknown driver event code %d " - "data %04x\n", channel->channel, ev_sub_code, - ev_sub_data); - break; - } -} - -int falcon_process_eventq(struct efx_channel *channel, int rx_quota) -{ - unsigned int read_ptr; - efx_qword_t event, *p_event; - int ev_code; - int rx_packets = 0; - - read_ptr = channel->eventq_read_ptr; - - do { - p_event = falcon_event(channel, read_ptr); - event = *p_event; - - if (!falcon_event_present(&event)) - /* End of events */ - break; - - EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n", - channel->channel, EFX_QWORD_VAL(event)); - - /* Clear this event by marking it all ones */ - EFX_SET_QWORD(*p_event); - - ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); - - switch (ev_code) { - case FSE_AZ_EV_CODE_RX_EV: - falcon_handle_rx_event(channel, &event); - ++rx_packets; - break; - case FSE_AZ_EV_CODE_TX_EV: - falcon_handle_tx_event(channel, &event); - break; - case FSE_AZ_EV_CODE_DRV_GEN_EV: - channel->eventq_magic = EFX_QWORD_FIELD( - event, FSF_AZ_DRV_GEN_EV_MAGIC); - EFX_LOG(channel->efx, "channel %d received generated " - "event "EFX_QWORD_FMT"\n", channel->channel, - EFX_QWORD_VAL(event)); - break; - case FSE_AZ_EV_CODE_GLOBAL_EV: - falcon_handle_global_event(channel, &event); - break; - case FSE_AZ_EV_CODE_DRIVER_EV: - falcon_handle_driver_event(channel, &event); - break; - default: - EFX_ERR(channel->efx, "channel %d unknown event type %d" - " (data " EFX_QWORD_FMT ")\n", channel->channel, - ev_code, EFX_QWORD_VAL(event)); - } - - /* Increment read pointer */ - read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; - - } while (rx_packets < rx_quota); - - channel->eventq_read_ptr = read_ptr; - return rx_packets; -} - -void falcon_set_int_moderation(struct efx_channel *channel) +static void falcon_push_irq_moderation(struct efx_channel *channel) { efx_dword_t timer_cmd; struct efx_nic *efx = channel->efx; @@ -1067,265 +120,18 @@ void falcon_set_int_moderation(struct efx_channel *channel) BUILD_BUG_ON(FR_AA_TIMER_COMMAND_KER != FR_BZ_TIMER_COMMAND_P0); efx_writed_page_locked(efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0, channel->channel); - -} - -/* Allocate buffer table entries for event queue */ -int falcon_probe_eventq(struct efx_channel *channel) -{ - struct efx_nic *efx = channel->efx; - BUILD_BUG_ON(EFX_EVQ_SIZE < 512 || EFX_EVQ_SIZE > 32768 || - EFX_EVQ_SIZE & EFX_EVQ_MASK); - return falcon_alloc_special_buffer(efx, &channel->eventq, - EFX_EVQ_SIZE * sizeof(efx_qword_t)); -} - -void falcon_init_eventq(struct efx_channel *channel) -{ - efx_oword_t evq_ptr; - struct efx_nic *efx = channel->efx; - - EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", - channel->channel, channel->eventq.index, - channel->eventq.index + channel->eventq.entries - 1); - - /* Pin event queue buffer */ - falcon_init_special_buffer(efx, &channel->eventq); - - /* Fill event queue with all ones (i.e. empty events) */ - memset(channel->eventq.addr, 0xff, channel->eventq.len); - - /* Push event queue to card */ - EFX_POPULATE_OWORD_3(evq_ptr, - FRF_AZ_EVQ_EN, 1, - FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries), - FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index); - efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base, - channel->channel); - - falcon_set_int_moderation(channel); -} - -void falcon_fini_eventq(struct efx_channel *channel) -{ - efx_oword_t eventq_ptr; - struct efx_nic *efx = channel->efx; - - /* Remove event queue from card */ - EFX_ZERO_OWORD(eventq_ptr); - efx_writeo_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base, - channel->channel); - - /* Unpin event queue */ - falcon_fini_special_buffer(efx, &channel->eventq); -} - -/* Free buffers backing event queue */ -void falcon_remove_eventq(struct efx_channel *channel) -{ - falcon_free_special_buffer(channel->efx, &channel->eventq); -} - - -/* Generates a test event on the event queue. A subsequent call to - * process_eventq() should pick up the event and place the value of - * "magic" into channel->eventq_magic; - */ -void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) -{ - efx_qword_t test_event; - - EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE, - FSE_AZ_EV_CODE_DRV_GEN_EV, - FSF_AZ_DRV_GEN_EV_MAGIC, magic); - falcon_generate_event(channel, &test_event); -} - -void falcon_sim_phy_event(struct efx_nic *efx) -{ - efx_qword_t phy_event; - - EFX_POPULATE_QWORD_1(phy_event, FSF_AZ_EV_CODE, - FSE_AZ_EV_CODE_GLOBAL_EV); - if (EFX_IS10G(efx)) - EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_XG_PHY0_INTR, 1); - else - EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_G_PHY0_INTR, 1); - - falcon_generate_event(&efx->channel[0], &phy_event); -} - -/************************************************************************** - * - * Flush handling - * - **************************************************************************/ - - -static void falcon_poll_flush_events(struct efx_nic *efx) -{ - struct efx_channel *channel = &efx->channel[0]; - struct efx_tx_queue *tx_queue; - struct efx_rx_queue *rx_queue; - unsigned int read_ptr = channel->eventq_read_ptr; - unsigned int end_ptr = (read_ptr - 1) & EFX_EVQ_MASK; - - do { - efx_qword_t *event = falcon_event(channel, read_ptr); - int ev_code, ev_sub_code, ev_queue; - bool ev_failed; - - if (!falcon_event_present(event)) - break; - - ev_code = EFX_QWORD_FIELD(*event, FSF_AZ_EV_CODE); - ev_sub_code = EFX_QWORD_FIELD(*event, - FSF_AZ_DRIVER_EV_SUBCODE); - if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV && - ev_sub_code == FSE_AZ_TX_DESCQ_FLS_DONE_EV) { - ev_queue = EFX_QWORD_FIELD(*event, - FSF_AZ_DRIVER_EV_SUBDATA); - if (ev_queue < EFX_TX_QUEUE_COUNT) { - tx_queue = efx->tx_queue + ev_queue; - tx_queue->flushed = true; - } - } else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV && - ev_sub_code == FSE_AZ_RX_DESCQ_FLS_DONE_EV) { - ev_queue = EFX_QWORD_FIELD( - *event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID); - ev_failed = EFX_QWORD_FIELD( - *event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL); - if (ev_queue < efx->n_rx_queues) { - rx_queue = efx->rx_queue + ev_queue; - - /* retry the rx flush */ - if (ev_failed) - falcon_flush_rx_queue(rx_queue); - else - rx_queue->flushed = true; - } - } - - read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; - } while (read_ptr != end_ptr); -} - -/* Handle tx and rx flushes at the same time, since they run in - * parallel in the hardware and there's no reason for us to - * serialise them */ -int falcon_flush_queues(struct efx_nic *efx) -{ - struct efx_rx_queue *rx_queue; - struct efx_tx_queue *tx_queue; - int i; - bool outstanding; - - /* Issue flush requests */ - efx_for_each_tx_queue(tx_queue, efx) { - tx_queue->flushed = false; - falcon_flush_tx_queue(tx_queue); - } - efx_for_each_rx_queue(rx_queue, efx) { - rx_queue->flushed = false; - falcon_flush_rx_queue(rx_queue); - } - - /* Poll the evq looking for flush completions. Since we're not pushing - * any more rx or tx descriptors at this point, we're in no danger of - * overflowing the evq whilst we wait */ - for (i = 0; i < FALCON_FLUSH_POLL_COUNT; ++i) { - msleep(FALCON_FLUSH_INTERVAL); - falcon_poll_flush_events(efx); - - /* Check if every queue has been succesfully flushed */ - outstanding = false; - efx_for_each_tx_queue(tx_queue, efx) - outstanding |= !tx_queue->flushed; - efx_for_each_rx_queue(rx_queue, efx) - outstanding |= !rx_queue->flushed; - if (!outstanding) - return 0; - } - - /* Mark the queues as all flushed. We're going to return failure - * leading to a reset, or fake up success anyway. "flushed" now - * indicates that we tried to flush. */ - efx_for_each_tx_queue(tx_queue, efx) { - if (!tx_queue->flushed) - EFX_ERR(efx, "tx queue %d flush command timed out\n", - tx_queue->queue); - tx_queue->flushed = true; - } - efx_for_each_rx_queue(rx_queue, efx) { - if (!rx_queue->flushed) - EFX_ERR(efx, "rx queue %d flush command timed out\n", - rx_queue->queue); - rx_queue->flushed = true; - } - - if (EFX_WORKAROUND_7803(efx)) - return 0; - - return -ETIMEDOUT; } -/************************************************************************** - * - * Falcon hardware interrupts - * The hardware interrupt handler does very little work; all the event - * queue processing is carried out by per-channel tasklets. - * - **************************************************************************/ +static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx); -/* Enable/disable/generate Falcon interrupts */ -static inline void falcon_interrupts(struct efx_nic *efx, int enabled, - int force) +static void falcon_prepare_flush(struct efx_nic *efx) { - efx_oword_t int_en_reg_ker; + falcon_deconfigure_mac_wrapper(efx); - EFX_POPULATE_OWORD_2(int_en_reg_ker, - FRF_AZ_KER_INT_KER, force, - FRF_AZ_DRV_INT_EN_KER, enabled); - efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); -} - -void falcon_enable_interrupts(struct efx_nic *efx) -{ - efx_oword_t int_adr_reg_ker; - struct efx_channel *channel; - - EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr)); - wmb(); /* Ensure interrupt vector is clear before interrupts enabled */ - - /* Program address */ - EFX_POPULATE_OWORD_2(int_adr_reg_ker, - FRF_AZ_NORM_INT_VEC_DIS_KER, - EFX_INT_MODE_USE_MSI(efx), - FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr); - efx_writeo(efx, &int_adr_reg_ker, FR_AZ_INT_ADR_KER); - - /* Enable interrupts */ - falcon_interrupts(efx, 1, 0); - - /* Force processing of all the channels to get the EVQ RPTRs up to - date */ - efx_for_each_channel(channel, efx) - efx_schedule_channel(channel); -} - -void falcon_disable_interrupts(struct efx_nic *efx) -{ - /* Disable interrupts */ - falcon_interrupts(efx, 0, 0); -} - -/* Generate a Falcon test interrupt - * Interrupt must already have been enabled, otherwise nasty things - * may happen. - */ -void falcon_generate_interrupt(struct efx_nic *efx) -{ - falcon_interrupts(efx, 1, 1); + /* Wait for the tx and rx fifo's to get to the next packet boundary + * (~1ms without back-pressure), then to drain the remainder of the + * fifo's at data path speeds (negligible), with a healthy margin. */ + msleep(10); } /* Acknowledge a legacy interrupt from Falcon @@ -1338,7 +144,7 @@ void falcon_generate_interrupt(struct efx_nic *efx) * * NB most hardware supports MSI interrupts */ -static inline void falcon_irq_ack_a1(struct efx_nic *efx) +inline void falcon_irq_ack_a1(struct efx_nic *efx) { efx_dword_t reg; @@ -1347,104 +153,8 @@ static inline void falcon_irq_ack_a1(struct efx_nic *efx) efx_readd(efx, ®, FR_AA_WORK_AROUND_BROKEN_PCI_READS); } -/* Process a fatal interrupt - * Disable bus mastering ASAP and schedule a reset - */ -static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx) -{ - struct falcon_nic_data *nic_data = efx->nic_data; - efx_oword_t *int_ker = efx->irq_status.addr; - efx_oword_t fatal_intr; - int error, mem_perr; - - efx_reado(efx, &fatal_intr, FR_AZ_FATAL_INTR_KER); - error = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_FATAL_INTR); - - EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status " - EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker), - EFX_OWORD_VAL(fatal_intr), - error ? "disabling bus mastering" : "no recognised error"); - if (error == 0) - goto out; - - /* If this is a memory parity error dump which blocks are offending */ - mem_perr = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER); - if (mem_perr) { - efx_oword_t reg; - efx_reado(efx, ®, FR_AZ_MEM_STAT); - EFX_ERR(efx, "SYSTEM ERROR: memory parity error " - EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg)); - } - - /* Disable both devices */ - pci_clear_master(efx->pci_dev); - if (FALCON_IS_DUAL_FUNC(efx)) - pci_clear_master(nic_data->pci_dev2); - falcon_disable_interrupts(efx); - - /* Count errors and reset or disable the NIC accordingly */ - if (efx->int_error_count == 0 || - time_after(jiffies, efx->int_error_expire)) { - efx->int_error_count = 0; - efx->int_error_expire = - jiffies + FALCON_INT_ERROR_EXPIRE * HZ; - } - if (++efx->int_error_count < FALCON_MAX_INT_ERRORS) { - EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n"); - efx_schedule_reset(efx, RESET_TYPE_INT_ERROR); - } else { - EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen." - "NIC will be disabled\n"); - efx_schedule_reset(efx, RESET_TYPE_DISABLE); - } -out: - return IRQ_HANDLED; -} - -/* Handle a legacy interrupt from Falcon - * Acknowledges the interrupt and schedule event queue processing. - */ -static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id) -{ - struct efx_nic *efx = dev_id; - efx_oword_t *int_ker = efx->irq_status.addr; - irqreturn_t result = IRQ_NONE; - struct efx_channel *channel; - efx_dword_t reg; - u32 queues; - int syserr; - - /* Read the ISR which also ACKs the interrupts */ - efx_readd(efx, ®, FR_BZ_INT_ISR0); - queues = EFX_EXTRACT_DWORD(reg, 0, 31); - - /* Check to see if we have a serious error condition */ - syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); - if (unlikely(syserr)) - return falcon_fatal_interrupt(efx); - - /* Schedule processing of any interrupting queues */ - efx_for_each_channel(channel, efx) { - if ((queues & 1) || - falcon_event_present( - falcon_event(channel, channel->eventq_read_ptr))) { - efx_schedule_channel(channel); - result = IRQ_HANDLED; - } - queues >>= 1; - } - - if (result == IRQ_HANDLED) { - efx->last_irq_cpu = raw_smp_processor_id(); - EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n", - irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg)); - } - - return result; -} - -static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) +irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) { struct efx_nic *efx = dev_id; efx_oword_t *int_ker = efx->irq_status.addr; @@ -1467,13 +177,13 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) /* Check to see if we have a serious error condition */ syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); if (unlikely(syserr)) - return falcon_fatal_interrupt(efx); + return efx_nic_fatal_interrupt(efx); /* Determine interrupting queues, clear interrupt status * register and acknowledge the device interrupt. */ - BUILD_BUG_ON(INT_EVQS_WIDTH > EFX_MAX_CHANNELS); - queues = EFX_OWORD_FIELD(*int_ker, INT_EVQS); + BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS); + queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q); EFX_ZERO_OWORD(*int_ker); wmb(); /* Ensure the vector is cleared before interrupt ack */ falcon_irq_ack_a1(efx); @@ -1489,126 +199,6 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) return IRQ_HANDLED; } - -/* Handle an MSI interrupt from Falcon - * - * Handle an MSI hardware interrupt. This routine schedules event - * queue processing. No interrupt acknowledgement cycle is necessary. - * Also, we never need to check that the interrupt is for us, since - * MSI interrupts cannot be shared. - */ -static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id) -{ - struct efx_channel *channel = dev_id; - struct efx_nic *efx = channel->efx; - efx_oword_t *int_ker = efx->irq_status.addr; - int syserr; - - efx->last_irq_cpu = raw_smp_processor_id(); - EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n", - irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); - - /* Check to see if we have a serious error condition */ - syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT); - if (unlikely(syserr)) - return falcon_fatal_interrupt(efx); - - /* Schedule processing of the channel */ - efx_schedule_channel(channel); - - return IRQ_HANDLED; -} - - -/* Setup RSS indirection table. - * This maps from the hash value of the packet to RXQ - */ -static void falcon_setup_rss_indir_table(struct efx_nic *efx) -{ - int i = 0; - unsigned long offset; - efx_dword_t dword; - - if (falcon_rev(efx) < FALCON_REV_B0) - return; - - for (offset = FR_BZ_RX_INDIRECTION_TBL; - offset < FR_BZ_RX_INDIRECTION_TBL + 0x800; - offset += 0x10) { - EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE, - i % efx->n_rx_queues); - efx_writed(efx, &dword, offset); - i++; - } -} - -/* Hook interrupt handler(s) - * Try MSI and then legacy interrupts. - */ -int falcon_init_interrupt(struct efx_nic *efx) -{ - struct efx_channel *channel; - int rc; - - if (!EFX_INT_MODE_USE_MSI(efx)) { - irq_handler_t handler; - if (falcon_rev(efx) >= FALCON_REV_B0) - handler = falcon_legacy_interrupt_b0; - else - handler = falcon_legacy_interrupt_a1; - - rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED, - efx->name, efx); - if (rc) { - EFX_ERR(efx, "failed to hook legacy IRQ %d\n", - efx->pci_dev->irq); - goto fail1; - } - return 0; - } - - /* Hook MSI or MSI-X interrupt */ - efx_for_each_channel(channel, efx) { - rc = request_irq(channel->irq, falcon_msi_interrupt, - IRQF_PROBE_SHARED, /* Not shared */ - channel->name, channel); - if (rc) { - EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq); - goto fail2; - } - } - - return 0; - - fail2: - efx_for_each_channel(channel, efx) - free_irq(channel->irq, channel); - fail1: - return rc; -} - -void falcon_fini_interrupt(struct efx_nic *efx) -{ - struct efx_channel *channel; - efx_oword_t reg; - - /* Disable MSI/MSI-X interrupts */ - efx_for_each_channel(channel, efx) { - if (channel->irq) - free_irq(channel->irq, channel); - } - - /* ACK legacy interrupt */ - if (falcon_rev(efx) >= FALCON_REV_B0) - efx_reado(efx, ®, FR_BZ_INT_ISR0); - else - falcon_irq_ack_a1(efx); - - /* Disable legacy interrupt */ - if (efx->legacy_irq) - free_irq(efx->legacy_irq, efx); -} - /************************************************************************** * * EEPROM/flash @@ -1652,11 +242,10 @@ static int falcon_spi_wait(struct efx_nic *efx) } } -int falcon_spi_cmd(const struct efx_spi_device *spi, +int falcon_spi_cmd(struct efx_nic *efx, const struct efx_spi_device *spi, unsigned int command, int address, const void *in, void *out, size_t len) { - struct efx_nic *efx = spi->efx; bool addressed = (address >= 0); bool reading = (out != NULL); efx_oword_t reg; @@ -1725,15 +314,15 @@ efx_spi_munge_command(const struct efx_spi_device *spi, } /* Wait up to 10 ms for buffered write completion */ -int falcon_spi_wait_write(const struct efx_spi_device *spi) +int +falcon_spi_wait_write(struct efx_nic *efx, const struct efx_spi_device *spi) { - struct efx_nic *efx = spi->efx; unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); u8 status; int rc; for (;;) { - rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, + rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); if (rc) return rc; @@ -1749,8 +338,8 @@ int falcon_spi_wait_write(const struct efx_spi_device *spi) } } -int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, - size_t len, size_t *retlen, u8 *buffer) +int falcon_spi_read(struct efx_nic *efx, const struct efx_spi_device *spi, + loff_t start, size_t len, size_t *retlen, u8 *buffer) { size_t block_len, pos = 0; unsigned int command; @@ -1760,7 +349,7 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, block_len = min(len - pos, FALCON_SPI_MAX_LEN); command = efx_spi_munge_command(spi, SPI_READ, start + pos); - rc = falcon_spi_cmd(spi, command, start + pos, NULL, + rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL, buffer + pos, block_len); if (rc) break; @@ -1779,8 +368,9 @@ int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, return rc; } -int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, - size_t len, size_t *retlen, const u8 *buffer) +int +falcon_spi_write(struct efx_nic *efx, const struct efx_spi_device *spi, + loff_t start, size_t len, size_t *retlen, const u8 *buffer) { u8 verify_buffer[FALCON_SPI_MAX_LEN]; size_t block_len, pos = 0; @@ -1788,24 +378,24 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, int rc = 0; while (pos < len) { - rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); if (rc) break; block_len = min(len - pos, falcon_spi_write_limit(spi, start + pos)); command = efx_spi_munge_command(spi, SPI_WRITE, start + pos); - rc = falcon_spi_cmd(spi, command, start + pos, + rc = falcon_spi_cmd(efx, spi, command, start + pos, buffer + pos, NULL, block_len); if (rc) break; - rc = falcon_spi_wait_write(spi); + rc = falcon_spi_wait_write(efx, spi); if (rc) break; command = efx_spi_munge_command(spi, SPI_READ, start + pos); - rc = falcon_spi_cmd(spi, command, start + pos, + rc = falcon_spi_cmd(efx, spi, command, start + pos, NULL, verify_buffer, block_len); if (memcmp(verify_buffer, buffer + pos, block_len)) { rc = -EIO; @@ -1834,12 +424,23 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, ************************************************************************** */ -static int falcon_reset_macs(struct efx_nic *efx) +static void falcon_push_multicast_hash(struct efx_nic *efx) { - efx_oword_t reg; + union efx_multicast_hash *mc_hash = &efx->multicast_hash; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + + efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0); + efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1); +} + +static void falcon_reset_macs(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t reg, mac_ctrl; int count; - if (falcon_rev(efx) < FALCON_REV_B0) { + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { /* It's not safe to use GLB_CTL_REG to reset the * macs, so instead use the internal MAC resets */ @@ -1851,7 +452,7 @@ static int falcon_reset_macs(struct efx_nic *efx) EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0); efx_writeo(efx, ®, FR_AB_GM_CFG1); udelay(1000); - return 0; + return; } else { EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1); efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); @@ -1860,22 +461,20 @@ static int falcon_reset_macs(struct efx_nic *efx) efx_reado(efx, ®, FR_AB_XM_GLB_CFG); if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) == 0) - return 0; + return; udelay(10); } EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); - return -ETIMEDOUT; } } - /* MAC stats will fail whilst the TX fifo is draining. Serialise - * the drain sequence with the statistics fetch */ - efx_stats_disable(efx); + /* Mac stats will fail whist the TX fifo is draining */ + WARN_ON(nic_data->stats_disable_count == 0); - efx_reado(efx, ®, FR_AB_MAC_CTRL); - EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1); - efx_writeo(efx, ®, FR_AB_MAC_CTRL); + efx_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL); + EFX_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1); + efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); efx_reado(efx, ®, FR_AB_GLB_CTL); EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1); @@ -1901,21 +500,16 @@ static int falcon_reset_macs(struct efx_nic *efx) udelay(10); } - efx_stats_enable(efx); - - /* If we've reset the EM block and the link is up, then - * we'll have to kick the XAUI link so the PHY can recover */ - if (efx->link_state.up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx)) - falcon_reset_xaui(efx); - - return 0; + /* Ensure the correct MAC is selected before statistics + * are re-enabled by the caller */ + efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL); } void falcon_drain_tx_fifo(struct efx_nic *efx) { efx_oword_t reg; - if ((falcon_rev(efx) < FALCON_REV_B0) || + if ((efx_nic_rev(efx) < EFX_REV_FALCON_B0) || (efx->loopback_mode != LOOPBACK_NONE)) return; @@ -1927,11 +521,11 @@ void falcon_drain_tx_fifo(struct efx_nic *efx) falcon_reset_macs(efx); } -void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) +static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) { efx_oword_t reg; - if (falcon_rev(efx) < FALCON_REV_B0) + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) return; /* Isolate the MAC -> RX */ @@ -1939,8 +533,8 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0); efx_writeo(efx, ®, FR_AZ_RX_CFG); - if (!efx->link_state.up) - falcon_drain_tx_fifo(efx); + /* Isolate TX -> MAC */ + falcon_drain_tx_fifo(efx); } void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) @@ -1948,7 +542,6 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) struct efx_link_state *link_state = &efx->link_state; efx_oword_t reg; int link_speed; - bool tx_fc; switch (link_state->speed) { case 10000: link_speed = 3; break; @@ -1968,7 +561,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) FRF_AB_MAC_SPEED, link_speed); /* On B0, MAC backpressure can be disabled and packets get * discarded. */ - if (falcon_rev(efx) >= FALCON_REV_B0) { + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, !link_state->up); } @@ -1976,40 +569,31 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) efx_writeo(efx, ®, FR_AB_MAC_CTRL); /* Restore the multicast hash registers. */ - falcon_set_multicast_hash(efx); + falcon_push_multicast_hash(efx); - /* Transmission of pause frames when RX crosses the threshold is - * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. - * Action on receipt of pause frames is controller by XM_DIS_FCNTL */ - tx_fc = !!(efx->link_state.fc & EFX_FC_TX); efx_reado(efx, ®, FR_AZ_RX_CFG); - EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, tx_fc); - + /* Enable XOFF signal from RX FIFO (we enabled it during NIC + * initialisation but it may read back as 0) */ + EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); /* Unisolate the MAC -> RX */ - if (falcon_rev(efx) >= FALCON_REV_B0) + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); efx_writeo(efx, ®, FR_AZ_RX_CFG); } -int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) +static void falcon_stats_request(struct efx_nic *efx) { + struct falcon_nic_data *nic_data = efx->nic_data; efx_oword_t reg; - u32 *dma_done; - int i; - if (disable_dma_stats) - return 0; + WARN_ON(nic_data->stats_pending); + WARN_ON(nic_data->stats_disable_count); - /* Statistics fetch will fail if the MAC is in TX drain */ - if (falcon_rev(efx) >= FALCON_REV_B0) { - efx_oword_t temp; - efx_reado(efx, &temp, FR_AB_MAC_CTRL); - if (EFX_OWORD_FIELD(temp, FRF_BB_TXFIFO_DRAIN_EN)) - return 0; - } + if (nic_data->stats_dma_done == NULL) + return; /* no mac selected */ - dma_done = (efx->stats_buffer.addr + done_offset); - *dma_done = FALCON_STATS_NOT_DONE; + *nic_data->stats_dma_done = FALCON_STATS_NOT_DONE; + nic_data->stats_pending = true; wmb(); /* ensure done flag is clear */ /* Initiate DMA transfer of stats */ @@ -2019,17 +603,90 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) efx->stats_buffer.dma_addr); efx_writeo(efx, ®, FR_AB_MAC_STAT_DMA); - /* Wait for transfer to complete */ - for (i = 0; i < 400; i++) { - if (*(volatile u32 *)dma_done == FALCON_STATS_DONE) { - rmb(); /* Ensure the stats are valid. */ - return 0; - } - udelay(10); + mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2)); +} + +static void falcon_stats_complete(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + + if (!nic_data->stats_pending) + return; + + nic_data->stats_pending = 0; + if (*nic_data->stats_dma_done == FALCON_STATS_DONE) { + rmb(); /* read the done flag before the stats */ + efx->mac_op->update_stats(efx); + } else { + EFX_ERR(efx, "timed out waiting for statistics\n"); } +} - EFX_ERR(efx, "timed out waiting for statistics\n"); - return -ETIMEDOUT; +static void falcon_stats_timer_func(unsigned long context) +{ + struct efx_nic *efx = (struct efx_nic *)context; + struct falcon_nic_data *nic_data = efx->nic_data; + + spin_lock(&efx->stats_lock); + + falcon_stats_complete(efx); + if (nic_data->stats_disable_count == 0) + falcon_stats_request(efx); + + spin_unlock(&efx->stats_lock); +} + +static void falcon_switch_mac(struct efx_nic *efx); + +static bool falcon_loopback_link_poll(struct efx_nic *efx) +{ + struct efx_link_state old_state = efx->link_state; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + WARN_ON(!LOOPBACK_INTERNAL(efx)); + + efx->link_state.fd = true; + efx->link_state.fc = efx->wanted_fc; + efx->link_state.up = true; + + if (efx->loopback_mode == LOOPBACK_GMAC) + efx->link_state.speed = 1000; + else + efx->link_state.speed = 10000; + + return !efx_link_state_equal(&efx->link_state, &old_state); +} + +static int falcon_reconfigure_port(struct efx_nic *efx) +{ + int rc; + + WARN_ON(efx_nic_rev(efx) > EFX_REV_FALCON_B0); + + /* Poll the PHY link state *before* reconfiguring it. This means we + * will pick up the correct speed (in loopback) to select the correct + * MAC. + */ + if (LOOPBACK_INTERNAL(efx)) + falcon_loopback_link_poll(efx); + else + efx->phy_op->poll(efx); + + falcon_stop_nic_stats(efx); + falcon_deconfigure_mac_wrapper(efx); + + falcon_switch_mac(efx); + + efx->phy_op->reconfigure(efx); + rc = efx->mac_op->reconfigure(efx); + BUG_ON(rc); + + falcon_start_nic_stats(efx); + + /* Synchronise efx->link_state with the kernel */ + efx_link_status_changed(efx); + + return 0; } /************************************************************************** @@ -2042,18 +699,18 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset) /* Wait for GMII access to complete */ static int falcon_gmii_wait(struct efx_nic *efx) { - efx_dword_t md_stat; + efx_oword_t md_stat; int count; /* wait upto 50ms - taken max from datasheet */ for (count = 0; count < 5000; count++) { - efx_readd(efx, &md_stat, FR_AB_MD_STAT); - if (EFX_DWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) { - if (EFX_DWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 || - EFX_DWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) { + efx_reado(efx, &md_stat, FR_AB_MD_STAT); + if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSY) == 0) { + if (EFX_OWORD_FIELD(md_stat, FRF_AB_MD_LNFL) != 0 || + EFX_OWORD_FIELD(md_stat, FRF_AB_MD_BSERR) != 0) { EFX_ERR(efx, "error from GMII access " - EFX_DWORD_FMT"\n", - EFX_DWORD_VAL(md_stat)); + EFX_OWORD_FMT"\n", + EFX_OWORD_VAL(md_stat)); return -EIO; } return 0; @@ -2075,7 +732,7 @@ static int falcon_mdio_write(struct net_device *net_dev, EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n", prtad, devad, addr, value); - spin_lock_bh(&efx->phy_lock); + mutex_lock(&efx->mdio_lock); /* Check MDIO not currently being accessed */ rc = falcon_gmii_wait(efx); @@ -2110,8 +767,8 @@ static int falcon_mdio_write(struct net_device *net_dev, udelay(10); } - out: - spin_unlock_bh(&efx->phy_lock); +out: + mutex_unlock(&efx->mdio_lock); return rc; } @@ -2123,7 +780,7 @@ static int falcon_mdio_read(struct net_device *net_dev, efx_oword_t reg; int rc; - spin_lock_bh(&efx->phy_lock); + mutex_lock(&efx->mdio_lock); /* Check MDIO not currently being accessed */ rc = falcon_gmii_wait(efx); @@ -2159,39 +816,20 @@ static int falcon_mdio_read(struct net_device *net_dev, prtad, devad, addr, rc); } - out: - spin_unlock_bh(&efx->phy_lock); +out: + mutex_unlock(&efx->mdio_lock); return rc; } -int falcon_switch_mac(struct efx_nic *efx) +static void falcon_clock_mac(struct efx_nic *efx) { - struct efx_mac_operations *old_mac_op = efx->mac_op; - efx_oword_t nic_stat; unsigned strap_val; - int rc = 0; - - /* Don't try to fetch MAC stats while we're switching MACs */ - efx_stats_disable(efx); - - /* Internal loopbacks override the phy speed setting */ - if (efx->loopback_mode == LOOPBACK_GMAC) { - efx->link_state.speed = 1000; - efx->link_state.fd = true; - } else if (LOOPBACK_INTERNAL(efx)) { - efx->link_state.speed = 10000; - efx->link_state.fd = true; - } - - WARN_ON(!mutex_is_locked(&efx->mac_lock)); - efx->mac_op = (EFX_IS10G(efx) ? - &falcon_xmac_operations : &falcon_gmac_operations); + efx_oword_t nic_stat; - /* Always push the NIC_STAT_REG setting even if the mac hasn't - * changed, because this function is run post online reset */ + /* Configure the NIC generated MAC clock correctly */ efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); strap_val = EFX_IS10G(efx) ? 5 : 3; - if (falcon_rev(efx) >= FALCON_REV_B0) { + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP_EN, 1); EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP, strap_val); efx_writeo(efx, &nic_stat, FR_AB_NIC_STAT); @@ -2201,22 +839,39 @@ int falcon_switch_mac(struct efx_nic *efx) BUG_ON(EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_PINS) != strap_val); } +} + +static void falcon_switch_mac(struct efx_nic *efx) +{ + struct efx_mac_operations *old_mac_op = efx->mac_op; + struct falcon_nic_data *nic_data = efx->nic_data; + unsigned int stats_done_offset; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + WARN_ON(nic_data->stats_disable_count == 0); + + efx->mac_op = (EFX_IS10G(efx) ? + &falcon_xmac_operations : &falcon_gmac_operations); + + if (EFX_IS10G(efx)) + stats_done_offset = XgDmaDone_offset; + else + stats_done_offset = GDmaDone_offset; + nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset; if (old_mac_op == efx->mac_op) - goto out; + return; + + falcon_clock_mac(efx); EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G'); /* Not all macs support a mac-level link state */ - efx->mac_up = true; - - rc = falcon_reset_macs(efx); -out: - efx_stats_enable(efx); - return rc; + efx->xmac_poll_required = false; + falcon_reset_macs(efx); } /* This call is responsible for hooking in the MAC and PHY operations */ -int falcon_probe_port(struct efx_nic *efx) +static int falcon_probe_port(struct efx_nic *efx) { int rc; @@ -2238,29 +893,26 @@ int falcon_probe_port(struct efx_nic *efx) return -ENODEV; } - if (efx->phy_op->macs & EFX_XMAC) - efx->loopback_modes |= ((1 << LOOPBACK_XGMII) | - (1 << LOOPBACK_XGXS) | - (1 << LOOPBACK_XAUI)); - if (efx->phy_op->macs & EFX_GMAC) - efx->loopback_modes |= (1 << LOOPBACK_GMAC); - efx->loopback_modes |= efx->phy_op->loopbacks; - - /* Set up MDIO structure for PHY */ - efx->mdio.mmds = efx->phy_op->mmds; - efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + /* Fill out MDIO structure and loopback modes */ efx->mdio.mdio_read = falcon_mdio_read; efx->mdio.mdio_write = falcon_mdio_write; + rc = efx->phy_op->probe(efx); + if (rc != 0) + return rc; + + /* Initial assumption */ + efx->link_state.speed = 10000; + efx->link_state.fd = true; /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ - if (falcon_rev(efx) >= FALCON_REV_B0) + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; else efx->wanted_fc = EFX_FC_RX; /* Allocate buffer for stats */ - rc = falcon_alloc_buffer(efx, &efx->stats_buffer, - FALCON_MAC_STATS_SIZE); + rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, + FALCON_MAC_STATS_SIZE); if (rc) return rc; EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n", @@ -2271,40 +923,19 @@ int falcon_probe_port(struct efx_nic *efx) return 0; } -void falcon_remove_port(struct efx_nic *efx) +static void falcon_remove_port(struct efx_nic *efx) { - falcon_free_buffer(efx, &efx->stats_buffer); -} - -/************************************************************************** - * - * Multicast filtering - * - ************************************************************************** - */ - -void falcon_set_multicast_hash(struct efx_nic *efx) -{ - union efx_multicast_hash *mc_hash = &efx->multicast_hash; - - /* Broadcast packets go through the multicast hash filter. - * ether_crc_le() of the broadcast address is 0xbe2612ff - * so we always add bit 0xff to the mask. - */ - set_bit_le(0xff, mc_hash->byte); - - efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0); - efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1); + efx_nic_free_buffer(efx, &efx->stats_buffer); } - /************************************************************************** * * Falcon test code * **************************************************************************/ -int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) +static int +falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) { struct falcon_nvconfig *nvconfig; struct efx_spi_device *spi; @@ -2323,7 +954,7 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) nvconfig = region + FALCON_NVCONFIG_OFFSET; mutex_lock(&efx->spi_lock); - rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region); + rc = falcon_spi_read(efx, spi, 0, FALCON_NVCONFIG_END, NULL, region); mutex_unlock(&efx->spi_lock); if (rc) { EFX_ERR(efx, "Failed to read %s\n", @@ -2367,11 +998,12 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) return rc; } -/* Registers tested in the falcon register test */ -static struct { - unsigned address; - efx_oword_t mask; -} efx_test_registers[] = { +static int falcon_test_nvram(struct efx_nic *efx) +{ + return falcon_read_nvram(efx, NULL); +} + +static const struct efx_nic_register_test falcon_b0_register_tests[] = { { FR_AZ_ADR_REGION, EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, { FR_AZ_RX_CFG, @@ -2410,64 +1042,10 @@ static struct { EFX_OWORD32(0x0003FF0F, 0x00000000, 0x00000000, 0x00000000) }, }; -static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, - const efx_oword_t *mask) -{ - return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) || - ((a->u64[1] ^ b->u64[1]) & mask->u64[1]); -} - -int falcon_test_registers(struct efx_nic *efx) +static int falcon_b0_test_registers(struct efx_nic *efx) { - unsigned address = 0, i, j; - efx_oword_t mask, imask, original, reg, buf; - - /* Falcon should be in loopback to isolate the XMAC from the PHY */ - WARN_ON(!LOOPBACK_INTERNAL(efx)); - - for (i = 0; i < ARRAY_SIZE(efx_test_registers); ++i) { - address = efx_test_registers[i].address; - mask = imask = efx_test_registers[i].mask; - EFX_INVERT_OWORD(imask); - - efx_reado(efx, &original, address); - - /* bit sweep on and off */ - for (j = 0; j < 128; j++) { - if (!EFX_EXTRACT_OWORD32(mask, j, j)) - continue; - - /* Test this testable bit can be set in isolation */ - EFX_AND_OWORD(reg, original, mask); - EFX_SET_OWORD32(reg, j, j, 1); - - efx_writeo(efx, ®, address); - efx_reado(efx, &buf, address); - - if (efx_masked_compare_oword(®, &buf, &mask)) - goto fail; - - /* Test this testable bit can be cleared in isolation */ - EFX_OR_OWORD(reg, original, mask); - EFX_SET_OWORD32(reg, j, j, 0); - - efx_writeo(efx, ®, address); - efx_reado(efx, &buf, address); - - if (efx_masked_compare_oword(®, &buf, &mask)) - goto fail; - } - - efx_writeo(efx, &original, address); - } - - return 0; - -fail: - EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT - " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg), - EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask)); - return -EIO; + return efx_nic_test_registers(efx, falcon_b0_register_tests, + ARRAY_SIZE(falcon_b0_register_tests)); } /************************************************************************** @@ -2479,7 +1057,7 @@ fail: /* Resets NIC to known state. This routine must be called in process * context and is allowed to sleep. */ -int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) +static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) { struct falcon_nic_data *nic_data = efx->nic_data; efx_oword_t glb_ctl_reg_ker; @@ -2495,7 +1073,7 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) "function prior to hardware reset\n"); goto fail1; } - if (FALCON_IS_DUAL_FUNC(efx)) { + if (efx_nic_is_dual_func(efx)) { rc = pci_save_state(nic_data->pci_dev2); if (rc) { EFX_ERR(efx, "failed to backup PCI state of " @@ -2530,7 +1108,7 @@ int falcon_reset_hw(struct efx_nic *efx, enum reset_type method) /* Restore PCI configuration if needed */ if (method == RESET_TYPE_WORLD) { - if (FALCON_IS_DUAL_FUNC(efx)) { + if (efx_nic_is_dual_func(efx)) { rc = pci_restore_state(nic_data->pci_dev2); if (rc) { EFX_ERR(efx, "failed to restore PCI config for " @@ -2568,6 +1146,44 @@ fail5: return rc; } +static void falcon_monitor(struct efx_nic *efx) +{ + bool link_changed; + int rc; + + BUG_ON(!mutex_is_locked(&efx->mac_lock)); + + rc = falcon_board(efx)->type->monitor(efx); + if (rc) { + EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", + (rc == -ERANGE) ? "reported fault" : "failed"); + efx->phy_mode |= PHY_MODE_LOW_POWER; + rc = __efx_reconfigure_port(efx); + WARN_ON(rc); + } + + if (LOOPBACK_INTERNAL(efx)) + link_changed = falcon_loopback_link_poll(efx); + else + link_changed = efx->phy_op->poll(efx); + + if (link_changed) { + falcon_stop_nic_stats(efx); + falcon_deconfigure_mac_wrapper(efx); + + falcon_switch_mac(efx); + rc = efx->mac_op->reconfigure(efx); + BUG_ON(rc); + + falcon_start_nic_stats(efx); + + efx_link_status_changed(efx); + } + + if (EFX_IS10G(efx)) + falcon_poll_xmac(efx); +} + /* Zeroes out the SRAM contents. This routine must be called in * process context and is allowed to sleep. */ @@ -2634,8 +1250,6 @@ static int falcon_spi_device_init(struct efx_nic *efx, spi_device->block_size = 1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_BLOCK_SIZE); - - spi_device->efx = efx; } else { spi_device = NULL; } @@ -2645,7 +1259,6 @@ static int falcon_spi_device_init(struct efx_nic *efx, return 0; } - static void falcon_remove_spi_devices(struct efx_nic *efx) { kfree(efx->spi_eeprom); @@ -2715,49 +1328,6 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) return rc; } -/* Probe the NIC variant (revision, ASIC vs FPGA, function count, port - * count, port speed). Set workaround and feature flags accordingly. - */ -static int falcon_probe_nic_variant(struct efx_nic *efx) -{ - efx_oword_t altera_build; - efx_oword_t nic_stat; - - efx_reado(efx, &altera_build, FR_AZ_ALTERA_BUILD); - if (EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER)) { - EFX_ERR(efx, "Falcon FPGA not supported\n"); - return -ENODEV; - } - - efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); - - switch (falcon_rev(efx)) { - case FALCON_REV_A0: - case 0xff: - EFX_ERR(efx, "Falcon rev A0 not supported\n"); - return -ENODEV; - - case FALCON_REV_A1: - if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) { - EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n"); - return -ENODEV; - } - break; - - case FALCON_REV_B0: - break; - - default: - EFX_ERR(efx, "Unknown Falcon rev %d\n", falcon_rev(efx)); - return -ENODEV; - } - - /* Initial assumed speed */ - efx->link_state.speed = EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) ? 10000 : 1000; - - return 0; -} - /* Probe all SPI devices on the NIC */ static void falcon_probe_spi_devices(struct efx_nic *efx) { @@ -2797,7 +1367,7 @@ static void falcon_probe_spi_devices(struct efx_nic *efx) large_eeprom_type); } -int falcon_probe_nic(struct efx_nic *efx) +static int falcon_probe_nic(struct efx_nic *efx) { struct falcon_nic_data *nic_data; struct falcon_board *board; @@ -2809,15 +1379,33 @@ int falcon_probe_nic(struct efx_nic *efx) return -ENOMEM; efx->nic_data = nic_data; - /* Determine number of ports etc. */ - rc = falcon_probe_nic_variant(efx); - if (rc) + rc = -ENODEV; + + if (efx_nic_fpga_ver(efx) != 0) { + EFX_ERR(efx, "Falcon FPGA not supported\n"); goto fail1; + } - /* Probe secondary function if expected */ - if (FALCON_IS_DUAL_FUNC(efx)) { - struct pci_dev *dev = pci_dev_get(efx->pci_dev); + if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { + efx_oword_t nic_stat; + struct pci_dev *dev; + u8 pci_rev = efx->pci_dev->revision; + if ((pci_rev == 0xff) || (pci_rev == 0)) { + EFX_ERR(efx, "Falcon rev A0 not supported\n"); + goto fail1; + } + efx_reado(efx, &nic_stat, FR_AB_NIC_STAT); + if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) { + EFX_ERR(efx, "Falcon rev A1 1G not supported\n"); + goto fail1; + } + if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) { + EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n"); + goto fail1; + } + + dev = pci_dev_get(efx->pci_dev); while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID, dev))) { if (dev->bus == efx->pci_dev->bus && @@ -2841,7 +1429,7 @@ int falcon_probe_nic(struct efx_nic *efx) } /* Allocate memory for INT_KER */ - rc = falcon_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); + rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); if (rc) goto fail4; BUG_ON(efx->irq_status.dma_addr & 0x0f); @@ -2870,12 +1458,16 @@ int falcon_probe_nic(struct efx_nic *efx) if (rc) goto fail5; - rc = falcon_board(efx)->init(efx); + rc = falcon_board(efx)->type->init(efx); if (rc) { EFX_ERR(efx, "failed to initialise board\n"); goto fail6; } + nic_data->stats_disable_count = 1; + setup_timer(&nic_data->stats_timer, &falcon_stats_timer_func, + (unsigned long)efx); + return 0; fail6: @@ -2883,7 +1475,7 @@ int falcon_probe_nic(struct efx_nic *efx) memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); fail5: falcon_remove_spi_devices(efx); - falcon_free_buffer(efx, &efx->irq_status); + efx_nic_free_buffer(efx, &efx->irq_status); fail4: fail3: if (nic_data->pci_dev2) { @@ -2906,12 +1498,12 @@ static void falcon_init_rx_cfg(struct efx_nic *efx) const unsigned ctrl_xon_thr = 20; const unsigned ctrl_xoff_thr = 25; /* RX data FIFO thresholds (256-byte units; size varies) */ - int data_xon_thr = rx_xon_thresh_bytes >> 8; - int data_xoff_thr = rx_xoff_thresh_bytes >> 8; + int data_xon_thr = efx_nic_rx_xon_thresh >> 8; + int data_xoff_thr = efx_nic_rx_xoff_thresh >> 8; efx_oword_t reg; efx_reado(efx, ®, FR_AZ_RX_CFG); - if (falcon_rev(efx) <= FALCON_REV_A1) { + if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) { /* Data FIFO size is 5.5K */ if (data_xon_thr < 0) data_xon_thr = 512 >> 8; @@ -2939,6 +1531,9 @@ static void falcon_init_rx_cfg(struct efx_nic *efx) EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr); EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1); } + /* Always enable XOFF signal from RX FIFO. We enable + * or disable transmission of pause frames at the MAC. */ + EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1); efx_writeo(efx, ®, FR_AZ_RX_CFG); } @@ -2946,7 +1541,7 @@ static void falcon_init_rx_cfg(struct efx_nic *efx) * defining the descriptor cache sizes and number of RSS channels. * It does not set up any buffers, descriptor rings or event queues. */ -int falcon_init_nic(struct efx_nic *efx) +static int falcon_init_nic(struct efx_nic *efx) { efx_oword_t temp; int rc; @@ -2957,36 +1552,19 @@ int falcon_init_nic(struct efx_nic *efx) efx_writeo(efx, &temp, FR_AB_NIC_STAT); /* Set the source of the GMAC clock */ - if (falcon_rev(efx) == FALCON_REV_B0) { + if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) { efx_reado(efx, &temp, FR_AB_GPIO_CTL); EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true); efx_writeo(efx, &temp, FR_AB_GPIO_CTL); } + /* Select the correct MAC */ + falcon_clock_mac(efx); + rc = falcon_reset_sram(efx); if (rc) return rc; - /* Set positions of descriptor caches in SRAM. */ - EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8); - efx_writeo(efx, &temp, FR_AZ_SRM_TX_DC_CFG); - EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8); - efx_writeo(efx, &temp, FR_AZ_SRM_RX_DC_CFG); - - /* Set TX descriptor cache size. */ - BUILD_BUG_ON(TX_DC_ENTRIES != (16 << TX_DC_ENTRIES_ORDER)); - EFX_POPULATE_OWORD_1(temp, FRF_AZ_TX_DC_SIZE, TX_DC_ENTRIES_ORDER); - efx_writeo(efx, &temp, FR_AZ_TX_DC_CFG); - - /* Set RX descriptor cache size. Set low watermark to size-8, as - * this allows most efficient prefetching. - */ - BUILD_BUG_ON(RX_DC_ENTRIES != (16 << RX_DC_ENTRIES_ORDER)); - EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_SIZE, RX_DC_ENTRIES_ORDER); - efx_writeo(efx, &temp, FR_AZ_RX_DC_CFG); - EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_PF_LWM, RX_DC_ENTRIES - 8); - efx_writeo(efx, &temp, FR_AZ_RX_DC_PF_WM); - /* Clear the parity enables on the TX data fifos as * they produce false parity errors because of timing issues */ @@ -2996,19 +1574,6 @@ int falcon_init_nic(struct efx_nic *efx) efx_writeo(efx, &temp, FR_AZ_CSR_SPARE); } - /* Enable all the genuinely fatal interrupts. (They are still - * masked by the overall interrupt mask, controlled by - * falcon_interrupts()). - * - * Note: All other fatal interrupts are enabled - */ - EFX_POPULATE_OWORD_3(temp, - FRF_AZ_ILL_ADR_INT_KER_EN, 1, - FRF_AZ_RBUF_OWN_INT_KER_EN, 1, - FRF_AZ_TBUF_OWN_INT_KER_EN, 1); - EFX_INVERT_OWORD(temp); - efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER); - if (EFX_WORKAROUND_7244(efx)) { efx_reado(efx, &temp, FR_BZ_RX_FILTER_CTL); EFX_SET_OWORD_FIELD(temp, FRF_BZ_UDP_FULL_SRCH_LIMIT, 8); @@ -3018,8 +1583,6 @@ int falcon_init_nic(struct efx_nic *efx) efx_writeo(efx, &temp, FR_BZ_RX_FILTER_CTL); } - falcon_setup_rss_indir_table(efx); - /* XXX This is documented only for Falcon A0/A1 */ /* Setup RX. Wait for descriptor is broken and must * be disabled. RXDP recovery shouldn't be needed, but is. @@ -3031,24 +1594,6 @@ int falcon_init_nic(struct efx_nic *efx) EFX_SET_OWORD_FIELD(temp, FRF_AA_RX_ISCSI_DIS, 1); efx_writeo(efx, &temp, FR_AA_RX_SELF_RST); - /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be - * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q. - */ - efx_reado(efx, &temp, FR_AZ_TX_RESERVED); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0); - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1); - /* Enable SW_EV to inherit in char driver - assume harmless here */ - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1); - /* Prefetch threshold 2 => fetch when descriptor cache half empty */ - EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2); - /* Squash TX of packets of 16 bytes or less */ - if (falcon_rev(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx)) - EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); - efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); - /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16 * descriptors (which is bad). */ @@ -3059,21 +1604,23 @@ int falcon_init_nic(struct efx_nic *efx) falcon_init_rx_cfg(efx); /* Set destination of both TX and RX Flush events */ - if (falcon_rev(efx) >= FALCON_REV_B0) { + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); efx_writeo(efx, &temp, FR_BZ_DP_CTRL); } + efx_nic_init_common(efx); + return 0; } -void falcon_remove_nic(struct efx_nic *efx) +static void falcon_remove_nic(struct efx_nic *efx) { struct falcon_nic_data *nic_data = efx->nic_data; struct falcon_board *board = falcon_board(efx); int rc; - falcon_board(efx)->fini(efx); + board->type->fini(efx); /* Remove I2C adapter and clear it in preparation for a retry */ rc = i2c_del_adapter(&board->i2c_adap); @@ -3081,7 +1628,7 @@ void falcon_remove_nic(struct efx_nic *efx) memset(&board->i2c_adap, 0, sizeof(board->i2c_adap)); falcon_remove_spi_devices(efx); - falcon_free_buffer(efx, &efx->irq_status); + efx_nic_free_buffer(efx, &efx->irq_status); falcon_reset_hw(efx, RESET_TYPE_ALL); @@ -3096,13 +1643,86 @@ void falcon_remove_nic(struct efx_nic *efx) efx->nic_data = NULL; } -void falcon_update_nic_stats(struct efx_nic *efx) +static void falcon_update_nic_stats(struct efx_nic *efx) { + struct falcon_nic_data *nic_data = efx->nic_data; efx_oword_t cnt; + if (nic_data->stats_disable_count) + return; + efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP); efx->n_rx_nodesc_drop_cnt += EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT); + + if (nic_data->stats_pending && + *nic_data->stats_dma_done == FALCON_STATS_DONE) { + nic_data->stats_pending = false; + rmb(); /* read the done flag before the stats */ + efx->mac_op->update_stats(efx); + } +} + +void falcon_start_nic_stats(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + + spin_lock_bh(&efx->stats_lock); + if (--nic_data->stats_disable_count == 0) + falcon_stats_request(efx); + spin_unlock_bh(&efx->stats_lock); +} + +void falcon_stop_nic_stats(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + int i; + + might_sleep(); + + spin_lock_bh(&efx->stats_lock); + ++nic_data->stats_disable_count; + spin_unlock_bh(&efx->stats_lock); + + del_timer_sync(&nic_data->stats_timer); + + /* Wait enough time for the most recent transfer to + * complete. */ + for (i = 0; i < 4 && nic_data->stats_pending; i++) { + if (*nic_data->stats_dma_done == FALCON_STATS_DONE) + break; + msleep(1); + } + + spin_lock_bh(&efx->stats_lock); + falcon_stats_complete(efx); + spin_unlock_bh(&efx->stats_lock); +} + +static void falcon_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) +{ + falcon_board(efx)->type->set_id_led(efx, mode); +} + +/************************************************************************** + * + * Wake on LAN + * + ************************************************************************** + */ + +static void falcon_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol) +{ + wol->supported = 0; + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static int falcon_set_wol(struct efx_nic *efx, u32 type) +{ + if (type != 0) + return -EINVAL; + return 0; } /************************************************************************** @@ -3112,7 +1732,30 @@ void falcon_update_nic_stats(struct efx_nic *efx) ************************************************************************** */ -struct efx_nic_type falcon_a_nic_type = { +struct efx_nic_type falcon_a1_nic_type = { + .probe = falcon_probe_nic, + .remove = falcon_remove_nic, + .init = falcon_init_nic, + .fini = efx_port_dummy_op_void, + .monitor = falcon_monitor, + .reset = falcon_reset_hw, + .probe_port = falcon_probe_port, + .remove_port = falcon_remove_port, + .prepare_flush = falcon_prepare_flush, + .update_stats = falcon_update_nic_stats, + .start_stats = falcon_start_nic_stats, + .stop_stats = falcon_stop_nic_stats, + .set_id_led = falcon_set_id_led, + .push_irq_moderation = falcon_push_irq_moderation, + .push_multicast_hash = falcon_push_multicast_hash, + .reconfigure_port = falcon_reconfigure_port, + .get_wol = falcon_get_wol, + .set_wol = falcon_set_wol, + .resume_wol = efx_port_dummy_op_void, + .test_nvram = falcon_test_nvram, + .default_mac_ops = &falcon_xmac_operations, + + .revision = EFX_REV_FALCON_A1, .mem_map_size = 0x20000, .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER, .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER, @@ -3123,9 +1766,37 @@ struct efx_nic_type falcon_a_nic_type = { .rx_buffer_padding = 0x24, .max_interrupt_mode = EFX_INT_MODE_MSI, .phys_addr_channels = 4, + .tx_dc_base = 0x130000, + .rx_dc_base = 0x100000, + .offload_features = NETIF_F_IP_CSUM, + .reset_world_flags = ETH_RESET_IRQ, }; -struct efx_nic_type falcon_b_nic_type = { +struct efx_nic_type falcon_b0_nic_type = { + .probe = falcon_probe_nic, + .remove = falcon_remove_nic, + .init = falcon_init_nic, + .fini = efx_port_dummy_op_void, + .monitor = falcon_monitor, + .reset = falcon_reset_hw, + .probe_port = falcon_probe_port, + .remove_port = falcon_remove_port, + .prepare_flush = falcon_prepare_flush, + .update_stats = falcon_update_nic_stats, + .start_stats = falcon_start_nic_stats, + .stop_stats = falcon_stop_nic_stats, + .set_id_led = falcon_set_id_led, + .push_irq_moderation = falcon_push_irq_moderation, + .push_multicast_hash = falcon_push_multicast_hash, + .reconfigure_port = falcon_reconfigure_port, + .get_wol = falcon_get_wol, + .set_wol = falcon_set_wol, + .resume_wol = efx_port_dummy_op_void, + .test_registers = falcon_b0_test_registers, + .test_nvram = falcon_test_nvram, + .default_mac_ops = &falcon_xmac_operations, + + .revision = EFX_REV_FALCON_B0, /* Map everything up to and including the RSS indirection * table. Don't map MSI-X table, MSI-X PBA since Linux * requires that they not be mapped. */ @@ -3143,5 +1814,9 @@ struct efx_nic_type falcon_b_nic_type = { .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy * interrupt handler only supports 32 * channels */ + .tx_dc_base = 0x130000, + .rx_dc_base = 0x100000, + .offload_features = NETIF_F_IP_CSUM, + .reset_world_flags = ETH_RESET_IRQ, }; diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h deleted file mode 100644 index 0da5ea7908b..00000000000 --- a/drivers/net/sfc/falcon.h +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************************** - * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -#ifndef EFX_FALCON_H -#define EFX_FALCON_H - -#include <linux/i2c-algo-bit.h> -#include "net_driver.h" -#include "efx.h" - -/* - * Falcon hardware control - */ - -enum falcon_revision { - FALCON_REV_A0 = 0, - FALCON_REV_A1 = 1, - FALCON_REV_B0 = 2, -}; - -static inline int falcon_rev(struct efx_nic *efx) -{ - return efx->pci_dev->revision; -} - -/** - * struct falcon_board - board information - * @type: Board model type - * @major: Major rev. ('A', 'B' ...) - * @minor: Minor rev. (0, 1, ...) - * @init: Allocate resources and initialise peripheral hardware - * @init_phy: Do board-specific PHY initialisation - * @set_id_led: Set state of identifying LED or revert to automatic function - * @monitor: Board-specific health check function - * @fini: Shut down hardware and free resources - * @i2c_adap: I2C adapter for on-board peripherals - * @i2c_data: Data for bit-banging algorithm - * @hwmon_client: I2C client for hardware monitor - * @ioexp_client: I2C client for power/port control - */ -struct falcon_board { - int type; - int major; - int minor; - int (*init) (struct efx_nic *nic); - void (*init_phy) (struct efx_nic *efx); - void (*set_id_led) (struct efx_nic *efx, enum efx_led_mode mode); - int (*monitor) (struct efx_nic *nic); - void (*fini) (struct efx_nic *nic); - struct i2c_adapter i2c_adap; - struct i2c_algo_bit_data i2c_data; - struct i2c_client *hwmon_client, *ioexp_client; -}; - -/** - * struct falcon_nic_data - Falcon NIC state - * @pci_dev2: The secondary PCI device if present - * @board: Board state and functions - */ -struct falcon_nic_data { - struct pci_dev *pci_dev2; - struct falcon_board board; -}; - -static inline struct falcon_board *falcon_board(struct efx_nic *efx) -{ - struct falcon_nic_data *data = efx->nic_data; - return &data->board; -} - -extern struct efx_nic_type falcon_a_nic_type; -extern struct efx_nic_type falcon_b_nic_type; - -/************************************************************************** - * - * Externs - * - ************************************************************************** - */ - -extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info); - -/* TX data path */ -extern int falcon_probe_tx(struct efx_tx_queue *tx_queue); -extern void falcon_init_tx(struct efx_tx_queue *tx_queue); -extern void falcon_fini_tx(struct efx_tx_queue *tx_queue); -extern void falcon_remove_tx(struct efx_tx_queue *tx_queue); -extern void falcon_push_buffers(struct efx_tx_queue *tx_queue); - -/* RX data path */ -extern int falcon_probe_rx(struct efx_rx_queue *rx_queue); -extern void falcon_init_rx(struct efx_rx_queue *rx_queue); -extern void falcon_fini_rx(struct efx_rx_queue *rx_queue); -extern void falcon_remove_rx(struct efx_rx_queue *rx_queue); -extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue); - -/* Event data path */ -extern int falcon_probe_eventq(struct efx_channel *channel); -extern void falcon_init_eventq(struct efx_channel *channel); -extern void falcon_fini_eventq(struct efx_channel *channel); -extern void falcon_remove_eventq(struct efx_channel *channel); -extern int falcon_process_eventq(struct efx_channel *channel, int rx_quota); -extern void falcon_eventq_read_ack(struct efx_channel *channel); - -/* Ports */ -extern int falcon_probe_port(struct efx_nic *efx); -extern void falcon_remove_port(struct efx_nic *efx); - -/* MAC/PHY */ -extern int falcon_switch_mac(struct efx_nic *efx); -extern bool falcon_xaui_link_ok(struct efx_nic *efx); -extern int falcon_dma_stats(struct efx_nic *efx, - unsigned int done_offset); -extern void falcon_drain_tx_fifo(struct efx_nic *efx); -extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx); -extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); - -/* Interrupts and test events */ -extern int falcon_init_interrupt(struct efx_nic *efx); -extern void falcon_enable_interrupts(struct efx_nic *efx); -extern void falcon_generate_test_event(struct efx_channel *channel, - unsigned int magic); -extern void falcon_sim_phy_event(struct efx_nic *efx); -extern void falcon_generate_interrupt(struct efx_nic *efx); -extern void falcon_set_int_moderation(struct efx_channel *channel); -extern void falcon_disable_interrupts(struct efx_nic *efx); -extern void falcon_fini_interrupt(struct efx_nic *efx); - -#define FALCON_IRQ_MOD_RESOLUTION 5 - -/* Global Resources */ -extern int falcon_probe_nic(struct efx_nic *efx); -extern int falcon_init_nic(struct efx_nic *efx); -extern int falcon_flush_queues(struct efx_nic *efx); -extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method); -extern void falcon_remove_nic(struct efx_nic *efx); -extern void falcon_update_nic_stats(struct efx_nic *efx); -extern void falcon_set_multicast_hash(struct efx_nic *efx); -extern int falcon_reset_xaui(struct efx_nic *efx); - -/* Tests */ -struct falcon_nvconfig; -extern int falcon_read_nvram(struct efx_nic *efx, - struct falcon_nvconfig *nvconfig); -extern int falcon_test_registers(struct efx_nic *efx); - -/************************************************************************** - * - * Falcon MAC stats - * - ************************************************************************** - */ - -#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset) -#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH) - -/* Retrieve statistic from statistics block */ -#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \ - if (FALCON_STAT_WIDTH(falcon_stat) == 16) \ - (efx)->mac_stats.efx_stat += le16_to_cpu( \ - *((__force __le16 *) \ - (efx->stats_buffer.addr + \ - FALCON_STAT_OFFSET(falcon_stat)))); \ - else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \ - (efx)->mac_stats.efx_stat += le32_to_cpu( \ - *((__force __le32 *) \ - (efx->stats_buffer.addr + \ - FALCON_STAT_OFFSET(falcon_stat)))); \ - else \ - (efx)->mac_stats.efx_stat += le64_to_cpu( \ - *((__force __le64 *) \ - (efx->stats_buffer.addr + \ - FALCON_STAT_OFFSET(falcon_stat)))); \ - } while (0) - -#define FALCON_MAC_STATS_SIZE 0x100 - -#define MAC_DATA_LBN 0 -#define MAC_DATA_WIDTH 32 - -extern void falcon_generate_event(struct efx_channel *channel, - efx_qword_t *event); - -#endif /* EFX_FALCON_H */ diff --git a/drivers/net/sfc/falcon_boards.c b/drivers/net/sfc/falcon_boards.c index 333ccc14e52..bf0b96af533 100644 --- a/drivers/net/sfc/falcon_boards.c +++ b/drivers/net/sfc/falcon_boards.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2008 Solarflare Communications Inc. + * Copyright 2007-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -12,7 +12,7 @@ #include "net_driver.h" #include "phy.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "regs.h" #include "io.h" #include "workarounds.h" @@ -144,7 +144,7 @@ static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask) */ /************************************************************************** - * Support for I2C IO Expander device on SFE40001 + * Support for I2C IO Expander device on SFE4001 */ #define PCA9539 0x74 @@ -347,14 +347,15 @@ static ssize_t set_phy_flash_cfg(struct device *dev, * MAC stats accordingly. */ efx->phy_mode = new_mode; if (new_mode & PHY_MODE_SPECIAL) - efx_stats_disable(efx); - if (falcon_board(efx)->type == FALCON_BOARD_SFE4001) + falcon_stop_nic_stats(efx); + if (falcon_board(efx)->type->id == FALCON_BOARD_SFE4001) err = sfe4001_poweron(efx); else err = sfn4111t_reset(efx); - efx_reconfigure_port(efx); + if (!err) + err = efx_reconfigure_port(efx); if (!(new_mode & PHY_MODE_SPECIAL)) - efx_stats_enable(efx); + falcon_start_nic_stats(efx); } rtnl_unlock(); @@ -380,7 +381,7 @@ static int sfe4001_check_hw(struct efx_nic *efx) s32 status; /* If XAUI link is up then do not monitor */ - if (EFX_WORKAROUND_7884(efx) && efx->mac_up) + if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required) return 0; /* Check the powered status of the PHY. Lack of power implies that @@ -438,17 +439,10 @@ static int sfe4001_init(struct efx_nic *efx) goto fail_hwmon; } - /* 10Xpress has fixed-function LED pins, so there is no board-specific - * blink code. */ - board->set_id_led = tenxpress_set_id_led; - - board->monitor = sfe4001_check_hw; - board->fini = sfe4001_fini; - if (efx->phy_mode & PHY_MODE_SPECIAL) { /* PHY won't generate a 156.25 MHz clock and MAC stats fetch * will fail. */ - efx_stats_disable(efx); + falcon_stop_nic_stats(efx); } rc = sfe4001_poweron(efx); if (rc) @@ -475,7 +469,7 @@ static int sfn4111t_check_hw(struct efx_nic *efx) s32 status; /* If XAUI link is up then do not monitor */ - if (EFX_WORKAROUND_7884(efx) && efx->mac_up) + if (EFX_WORKAROUND_7884(efx) && !efx->xmac_poll_required) return 0; /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */ @@ -511,7 +505,7 @@ static void sfn4111t_init_phy(struct efx_nic *efx) return; efx->phy_mode = PHY_MODE_SPECIAL; - efx_stats_disable(efx); + falcon_stop_nic_stats(efx); } sfn4111t_reset(efx); @@ -531,11 +525,6 @@ static int sfn4111t_init(struct efx_nic *efx) if (!board->hwmon_client) return -EIO; - board->init_phy = sfn4111t_init_phy; - board->set_id_led = tenxpress_set_id_led; - board->monitor = sfn4111t_check_hw; - board->fini = sfn4111t_fini; - rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); if (rc) goto fail_hwmon; @@ -543,7 +532,7 @@ static int sfn4111t_init(struct efx_nic *efx) if (efx->phy_mode & PHY_MODE_SPECIAL) /* PHY may not generate a 156.25 MHz clock and MAC * stats fetch will fail. */ - efx_stats_disable(efx); + falcon_stop_nic_stats(efx); return 0; @@ -620,15 +609,7 @@ static int sfe4002_check_hw(struct efx_nic *efx) static int sfe4002_init(struct efx_nic *efx) { - struct falcon_board *board = falcon_board(efx); - int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); - if (rc) - return rc; - board->monitor = sfe4002_check_hw; - board->init_phy = sfe4002_init_phy; - board->set_id_led = sfe4002_set_id_led; - board->fini = efx_fini_lm87; - return 0; + return efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); } /***************************************************************************** @@ -692,67 +673,80 @@ static int sfn4112f_check_hw(struct efx_nic *efx) static int sfn4112f_init(struct efx_nic *efx) { - struct falcon_board *board = falcon_board(efx); - - int rc = efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs); - if (rc) - return rc; - board->monitor = sfn4112f_check_hw; - board->init_phy = sfn4112f_init_phy; - board->set_id_led = sfn4112f_set_id_led; - board->fini = efx_fini_lm87; - return 0; + return efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs); } -/* This will get expanded as board-specific details get moved out of the - * PHY drivers. */ -struct falcon_board_data { - u8 type; - const char *ref_model; - const char *gen_type; - int (*init) (struct efx_nic *nic); -}; - - -static struct falcon_board_data board_data[] = { - { FALCON_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init }, - { FALCON_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init }, - { FALCON_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter", - sfn4111t_init }, - { FALCON_BOARD_SFN4112F, "SFN4112F", "SFP+ adapter", - sfn4112f_init }, +static const struct falcon_board_type board_types[] = { + { + .id = FALCON_BOARD_SFE4001, + .ref_model = "SFE4001", + .gen_type = "10GBASE-T adapter", + .init = sfe4001_init, + .init_phy = efx_port_dummy_op_void, + .fini = sfe4001_fini, + .set_id_led = tenxpress_set_id_led, + .monitor = sfe4001_check_hw, + }, + { + .id = FALCON_BOARD_SFE4002, + .ref_model = "SFE4002", + .gen_type = "XFP adapter", + .init = sfe4002_init, + .init_phy = sfe4002_init_phy, + .fini = efx_fini_lm87, + .set_id_led = sfe4002_set_id_led, + .monitor = sfe4002_check_hw, + }, + { + .id = FALCON_BOARD_SFN4111T, + .ref_model = "SFN4111T", + .gen_type = "100/1000/10GBASE-T adapter", + .init = sfn4111t_init, + .init_phy = sfn4111t_init_phy, + .fini = sfn4111t_fini, + .set_id_led = tenxpress_set_id_led, + .monitor = sfn4111t_check_hw, + }, + { + .id = FALCON_BOARD_SFN4112F, + .ref_model = "SFN4112F", + .gen_type = "SFP+ adapter", + .init = sfn4112f_init, + .init_phy = sfn4112f_init_phy, + .fini = efx_fini_lm87, + .set_id_led = sfn4112f_set_id_led, + .monitor = sfn4112f_check_hw, + }, }; -static struct falcon_board falcon_dummy_board = { +static const struct falcon_board_type falcon_dummy_board = { .init = efx_port_dummy_op_int, .init_phy = efx_port_dummy_op_void, + .fini = efx_port_dummy_op_void, .set_id_led = efx_port_dummy_op_set_id_led, .monitor = efx_port_dummy_op_int, - .fini = efx_port_dummy_op_void, }; void falcon_probe_board(struct efx_nic *efx, u16 revision_info) { struct falcon_board *board = falcon_board(efx); - struct falcon_board_data *data = NULL; + u8 type_id = FALCON_BOARD_TYPE(revision_info); int i; - *board = falcon_dummy_board; - board->type = FALCON_BOARD_TYPE(revision_info); board->major = FALCON_BOARD_MAJOR(revision_info); board->minor = FALCON_BOARD_MINOR(revision_info); - for (i = 0; i < ARRAY_SIZE(board_data); i++) - if (board_data[i].type == board->type) - data = &board_data[i]; + for (i = 0; i < ARRAY_SIZE(board_types); i++) + if (board_types[i].id == type_id) + board->type = &board_types[i]; - if (data) { + if (board->type) { EFX_INFO(efx, "board is %s rev %c%d\n", (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) - ? data->ref_model : data->gen_type, + ? board->type->ref_model : board->type->gen_type, 'A' + board->major, board->minor); - board->init = data->init; } else { - EFX_ERR(efx, "unknown board type %d\n", board->type); + EFX_ERR(efx, "unknown board type %d\n", type_id); + board->type = &falcon_dummy_board; } } diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c index 967f3fb397c..7dadfcbd6ce 100644 --- a/drivers/net/sfc/falcon_gmac.c +++ b/drivers/net/sfc/falcon_gmac.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -11,7 +11,7 @@ #include <linux/delay.h> #include "net_driver.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "mac.h" #include "regs.h" #include "io.h" @@ -22,7 +22,7 @@ * *************************************************************************/ -static void falcon_reconfigure_gmac(struct efx_nic *efx) +static int falcon_reconfigure_gmac(struct efx_nic *efx) { struct efx_link_state *link_state = &efx->link_state; bool loopback, tx_fc, rx_fc, bytemode; @@ -123,6 +123,8 @@ static void falcon_reconfigure_gmac(struct efx_nic *efx) udelay(10); falcon_reconfigure_mac_wrapper(efx); + + return 0; } static void falcon_update_stats_gmac(struct efx_nic *efx) @@ -130,11 +132,6 @@ static void falcon_update_stats_gmac(struct efx_nic *efx) struct efx_mac_stats *mac_stats = &efx->mac_stats; unsigned long old_rx_pause, old_tx_pause; unsigned long new_rx_pause, new_tx_pause; - int rc; - - rc = falcon_dma_stats(efx, GDmaDone_offset); - if (rc) - return; /* Pause frames are erroneously counted as errors (SFC bug 3269) */ old_rx_pause = mac_stats->rx_pause; @@ -221,9 +218,13 @@ static void falcon_update_stats_gmac(struct efx_nic *efx) mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64; } +static bool falcon_gmac_check_fault(struct efx_nic *efx) +{ + return false; +} + struct efx_mac_operations falcon_gmac_operations = { .reconfigure = falcon_reconfigure_gmac, .update_stats = falcon_update_stats_gmac, - .irq = efx_port_dummy_op_void, - .poll = efx_port_dummy_op_void, + .check_fault = falcon_gmac_check_fault, }; diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index 69cb55fc615..3da933f8f07 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -11,7 +11,7 @@ #include <linux/delay.h> #include "net_driver.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "regs.h" #include "io.h" #include "mac.h" @@ -60,11 +60,15 @@ static void falcon_setup_xaui(struct efx_nic *efx) int falcon_reset_xaui(struct efx_nic *efx) { + struct falcon_nic_data *nic_data = efx->nic_data; efx_oword_t reg; int count; + /* Don't fetch MAC statistics over an XMAC reset */ + WARN_ON(nic_data->stats_disable_count == 0); + /* Start reset sequence */ - EFX_POPULATE_DWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1); + EFX_POPULATE_OWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1); efx_writeo(efx, ®, FR_AB_XX_PWR_RST); /* Wait up to 10 ms for completion, then reinitialise */ @@ -85,7 +89,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) { efx_oword_t reg; - if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) + if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx)) return; /* We expect xgmii faults if the wireside link is up */ @@ -94,7 +98,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) /* We can only use this interrupt to signal the negative edge of * xaui_align [we have to poll the positive edge]. */ - if (!efx->mac_up) + if (efx->xmac_poll_required) return; /* Flush the ISR */ @@ -108,7 +112,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) } /* Get status of XAUI link */ -bool falcon_xaui_link_ok(struct efx_nic *efx) +static bool falcon_xaui_link_ok(struct efx_nic *efx) { efx_oword_t reg; bool align_done, link_ok = false; @@ -133,37 +137,38 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) /* If the link is up, then check the phy side of the xaui link */ if (efx->link_state.up && link_ok) - if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) + if (efx->mdio.mmds & (1 << MDIO_MMD_PHYXS)) link_ok = efx_mdio_phyxgxs_lane_sync(efx); return link_ok; } -static void falcon_reconfigure_xmac_core(struct efx_nic *efx) +void falcon_reconfigure_xmac_core(struct efx_nic *efx) { unsigned int max_frame_len; efx_oword_t reg; bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX); + bool tx_fc = !!(efx->link_state.fc & EFX_FC_TX); /* Configure MAC - cut-thru mode is hard wired on */ - EFX_POPULATE_DWORD_3(reg, + EFX_POPULATE_OWORD_3(reg, FRF_AB_XM_RX_JUMBO_MODE, 1, FRF_AB_XM_TX_STAT_EN, 1, FRF_AB_XM_RX_STAT_EN, 1); efx_writeo(efx, ®, FR_AB_XM_GLB_CFG); /* Configure TX */ - EFX_POPULATE_DWORD_6(reg, + EFX_POPULATE_OWORD_6(reg, FRF_AB_XM_TXEN, 1, FRF_AB_XM_TX_PRMBL, 1, FRF_AB_XM_AUTO_PAD, 1, FRF_AB_XM_TXCRC, 1, - FRF_AB_XM_FCNTL, 1, + FRF_AB_XM_FCNTL, tx_fc, FRF_AB_XM_IPG, 0x3); efx_writeo(efx, ®, FR_AB_XM_TX_CFG); /* Configure RX */ - EFX_POPULATE_DWORD_5(reg, + EFX_POPULATE_OWORD_5(reg, FRF_AB_XM_RXEN, 1, FRF_AB_XM_AUTO_DEPAD, 0, FRF_AB_XM_ACPT_ALL_MCAST, 1, @@ -173,14 +178,14 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx) /* Set frame length */ max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); - EFX_POPULATE_DWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len); + EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len); efx_writeo(efx, ®, FR_AB_XM_RX_PARAM); - EFX_POPULATE_DWORD_2(reg, + EFX_POPULATE_OWORD_2(reg, FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len, FRF_AB_XM_TX_JUMBO_MODE, 1); efx_writeo(efx, ®, FR_AB_XM_TX_PARAM); - EFX_POPULATE_DWORD_2(reg, + EFX_POPULATE_OWORD_2(reg, FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */ FRF_AB_XM_DIS_FCNTL, !rx_fc); efx_writeo(efx, ®, FR_AB_XM_FC); @@ -239,28 +244,38 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) } -/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails - * to come back up. Bash it until it comes back up */ -static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries) +/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */ +static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries) { - efx->mac_up = falcon_xaui_link_ok(efx); + bool mac_up = falcon_xaui_link_ok(efx); - if ((efx->loopback_mode == LOOPBACK_NETWORK) || + if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS || efx_phy_mode_disabled(efx->phy_mode)) /* XAUI link is expected to be down */ - return; + return mac_up; - while (!efx->mac_up && tries) { + falcon_stop_nic_stats(efx); + + while (!mac_up && tries) { EFX_LOG(efx, "bashing xaui\n"); falcon_reset_xaui(efx); udelay(200); - efx->mac_up = falcon_xaui_link_ok(efx); + mac_up = falcon_xaui_link_ok(efx); --tries; } + + falcon_start_nic_stats(efx); + + return mac_up; +} + +static bool falcon_xmac_check_fault(struct efx_nic *efx) +{ + return !falcon_check_xaui_link_up(efx, 5); } -static void falcon_reconfigure_xmac(struct efx_nic *efx) +static int falcon_reconfigure_xmac(struct efx_nic *efx) { falcon_mask_status_intr(efx, false); @@ -269,18 +284,15 @@ static void falcon_reconfigure_xmac(struct efx_nic *efx) falcon_reconfigure_mac_wrapper(efx); - falcon_check_xaui_link_up(efx, 5); + efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5); falcon_mask_status_intr(efx, true); + + return 0; } static void falcon_update_stats_xmac(struct efx_nic *efx) { struct efx_mac_stats *mac_stats = &efx->mac_stats; - int rc; - - rc = falcon_dma_stats(efx, XgDmaDone_offset); - if (rc) - return; /* Update MAC stats from DMAed values */ FALCON_STAT(efx, XgRxOctets, rx_bytes); @@ -338,35 +350,19 @@ static void falcon_update_stats_xmac(struct efx_nic *efx) mac_stats->rx_control * 64); } -static void falcon_xmac_irq(struct efx_nic *efx) -{ - /* The XGMII link has a transient fault, which indicates either: - * - there's a transient xgmii fault - * - falcon's end of the xaui link may need a kick - * - the wire-side link may have gone down, but the lasi/poll() - * hasn't noticed yet. - * - * We only want to even bother polling XAUI if we're confident it's - * not (1) or (3). In both cases, the only reliable way to spot this - * is to wait a bit. We do this here by forcing the mac link state - * to down, and waiting for the mac poll to come round and check - */ - efx->mac_up = false; -} - -static void falcon_poll_xmac(struct efx_nic *efx) +void falcon_poll_xmac(struct efx_nic *efx) { - if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up || efx->mac_up) + if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up || + !efx->xmac_poll_required) return; falcon_mask_status_intr(efx, false); - falcon_check_xaui_link_up(efx, 1); + efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 1); falcon_mask_status_intr(efx, true); } struct efx_mac_operations falcon_xmac_operations = { .reconfigure = falcon_reconfigure_xmac, .update_stats = falcon_update_stats_xmac, - .irq = falcon_xmac_irq, - .poll = falcon_poll_xmac, + .check_fault = falcon_xmac_check_fault, }; diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index 4e7074278fe..f1aa5f37489 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -15,5 +15,9 @@ extern struct efx_mac_operations falcon_gmac_operations; extern struct efx_mac_operations falcon_xmac_operations; +extern struct efx_mac_operations efx_mcdi_mac_operations; +extern void falcon_reconfigure_xmac_core(struct efx_nic *efx); +extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, + u32 dma_len, int enable, int clear); #endif diff --git a/drivers/net/sfc/mcdi.c b/drivers/net/sfc/mcdi.c new file mode 100644 index 00000000000..683353b904c --- /dev/null +++ b/drivers/net/sfc/mcdi.c @@ -0,0 +1,1112 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2008-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include <linux/delay.h> +#include "net_driver.h" +#include "nic.h" +#include "io.h" +#include "regs.h" +#include "mcdi_pcol.h" +#include "phy.h" + +/************************************************************************** + * + * Management-Controller-to-Driver Interface + * + ************************************************************************** + */ + +/* Software-defined structure to the shared-memory */ +#define CMD_NOTIFY_PORT0 0 +#define CMD_NOTIFY_PORT1 4 +#define CMD_PDU_PORT0 0x008 +#define CMD_PDU_PORT1 0x108 +#define REBOOT_FLAG_PORT0 0x3f8 +#define REBOOT_FLAG_PORT1 0x3fc + +#define MCDI_RPC_TIMEOUT 10 /*seconds */ + +#define MCDI_PDU(efx) \ + (efx_port_num(efx) ? CMD_PDU_PORT1 : CMD_PDU_PORT0) +#define MCDI_DOORBELL(efx) \ + (efx_port_num(efx) ? CMD_NOTIFY_PORT1 : CMD_NOTIFY_PORT0) +#define MCDI_REBOOT_FLAG(efx) \ + (efx_port_num(efx) ? REBOOT_FLAG_PORT1 : REBOOT_FLAG_PORT0) + +#define SEQ_MASK \ + EFX_MASK32(EFX_WIDTH(MCDI_HEADER_SEQ)) + +static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) +{ + struct siena_nic_data *nic_data; + EFX_BUG_ON_PARANOID(efx_nic_rev(efx) < EFX_REV_SIENA_A0); + nic_data = efx->nic_data; + return &nic_data->mcdi; +} + +void efx_mcdi_init(struct efx_nic *efx) +{ + struct efx_mcdi_iface *mcdi; + + if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) + return; + + mcdi = efx_mcdi(efx); + init_waitqueue_head(&mcdi->wq); + spin_lock_init(&mcdi->iface_lock); + atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT); + mcdi->mode = MCDI_MODE_POLL; + + (void) efx_mcdi_poll_reboot(efx); +} + +static void efx_mcdi_copyin(struct efx_nic *efx, unsigned cmd, + const u8 *inbuf, size_t inlen) +{ + struct efx_mcdi_iface *mcdi = efx_mcdi(efx); + unsigned pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned doorbell = FR_CZ_MC_TREG_SMEM + MCDI_DOORBELL(efx); + unsigned int i; + efx_dword_t hdr; + u32 xflags, seqno; + + BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); + BUG_ON(inlen & 3 || inlen >= 0x100); + + seqno = mcdi->seqno & SEQ_MASK; + xflags = 0; + if (mcdi->mode == MCDI_MODE_EVENTS) + xflags |= MCDI_HEADER_XFLAGS_EVREQ; + + EFX_POPULATE_DWORD_6(hdr, + MCDI_HEADER_RESPONSE, 0, + MCDI_HEADER_RESYNC, 1, + MCDI_HEADER_CODE, cmd, + MCDI_HEADER_DATALEN, inlen, + MCDI_HEADER_SEQ, seqno, + MCDI_HEADER_XFLAGS, xflags); + + efx_writed(efx, &hdr, pdu); + + for (i = 0; i < inlen; i += 4) + _efx_writed(efx, *((__le32 *)(inbuf + i)), pdu + 4 + i); + + /* Ensure the payload is written out before the header */ + wmb(); + + /* ring the doorbell with a distinctive value */ + _efx_writed(efx, (__force __le32) 0x45789abc, doorbell); +} + +static void efx_mcdi_copyout(struct efx_nic *efx, u8 *outbuf, size_t outlen) +{ + struct efx_mcdi_iface *mcdi = efx_mcdi(efx); + unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + int i; + + BUG_ON(atomic_read(&mcdi->state) == MCDI_STATE_QUIESCENT); + BUG_ON(outlen & 3 || outlen >= 0x100); + + for (i = 0; i < outlen; i += 4) + *((__le32 *)(outbuf + i)) = _efx_readd(efx, pdu + 4 + i); +} + +static int efx_mcdi_poll(struct efx_nic *efx) +{ + struct efx_mcdi_iface *mcdi = efx_mcdi(efx); + unsigned int time, finish; + unsigned int respseq, respcmd, error; + unsigned int pdu = FR_CZ_MC_TREG_SMEM + MCDI_PDU(efx); + unsigned int rc, spins; + efx_dword_t reg; + + /* Check for a reboot atomically with respect to efx_mcdi_copyout() */ + rc = efx_mcdi_poll_reboot(efx); + if (rc) + goto out; + + /* Poll for completion. Poll quickly (once a us) for the 1st jiffy, + * because generally mcdi responses are fast. After that, back off + * and poll once a jiffy (approximately) + */ + spins = TICK_USEC; + finish = get_seconds() + MCDI_RPC_TIMEOUT; + + while (1) { + if (spins != 0) { + --spins; + udelay(1); + } else + schedule(); + + time = get_seconds(); + + rmb(); + efx_readd(efx, ®, pdu); + + /* All 1's indicates that shared memory is in reset (and is + * not a valid header). Wait for it to come out reset before + * completing the command */ + if (EFX_DWORD_FIELD(reg, EFX_DWORD_0) != 0xffffffff && + EFX_DWORD_FIELD(reg, MCDI_HEADER_RESPONSE)) + break; + + if (time >= finish) + return -ETIMEDOUT; + } + + mcdi->resplen = EFX_DWORD_FIELD(reg, MCDI_HEADER_DATALEN); + respseq = EFX_DWORD_FIELD(reg, MCDI_HEADER_SEQ); + respcmd = EFX_DWORD_FIELD(reg, MCDI_HEADER_CODE); + error = EFX_DWORD_FIELD(reg, MCDI_HEADER_ERROR); + + if (error && mcdi->resplen == 0) { + EFX_ERR(efx, "MC rebooted\n"); + rc = EIO; + } else if ((respseq ^ mcdi->seqno) & SEQ_MASK) { + EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx seq 0x%x\n", + respseq, mcdi->seqno); + rc = EIO; + } else if (error) { + efx_readd(efx, ®, pdu + 4); + switch (EFX_DWORD_FIELD(reg, EFX_DWORD_0)) { +#define TRANSLATE_ERROR(name) \ + case MC_CMD_ERR_ ## name: \ + rc = name; \ + break + TRANSLATE_ERROR(ENOENT); + TRANSLATE_ERROR(EINTR); + TRANSLATE_ERROR(EACCES); + TRANSLATE_ERROR(EBUSY); + TRANSLATE_ERROR(EINVAL); + TRANSLATE_ERROR(EDEADLK); + TRANSLATE_ERROR(ENOSYS); + TRANSLATE_ERROR(ETIME); +#undef TRANSLATE_ERROR + default: + rc = EIO; + break; + } + } else + rc = 0; + +out: + mcdi->resprc = rc; + if (rc) + mcdi->resplen = 0; + + /* Return rc=0 like wait_event_timeout() */ + return 0; +} + +/* Test and clear MC-rebooted flag for this port/function */ +int efx_mcdi_poll_reboot(struct efx_nic *efx) +{ + unsigned int addr = FR_CZ_MC_TREG_SMEM + MCDI_REBOOT_FLAG(efx); + efx_dword_t reg; + uint32_t value; + + if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) + return false; + + efx_readd(efx, ®, addr); + value = EFX_DWORD_FIELD(reg, EFX_DWORD_0); + + if (value == 0) + return 0; + + EFX_ZERO_DWORD(reg); + efx_writed(efx, ®, addr); + + if (value == MC_STATUS_DWORD_ASSERT) + return -EINTR; + else + return -EIO; +} + +static void efx_mcdi_acquire(struct efx_mcdi_iface *mcdi) +{ + /* Wait until the interface becomes QUIESCENT and we win the race + * to mark it RUNNING. */ + wait_event(mcdi->wq, + atomic_cmpxchg(&mcdi->state, + MCDI_STATE_QUIESCENT, + MCDI_STATE_RUNNING) + == MCDI_STATE_QUIESCENT); +} + +static int efx_mcdi_await_completion(struct efx_nic *efx) +{ + struct efx_mcdi_iface *mcdi = efx_mcdi(efx); + + if (wait_event_timeout( + mcdi->wq, + atomic_read(&mcdi->state) == MCDI_STATE_COMPLETED, + msecs_to_jiffies(MCDI_RPC_TIMEOUT * 1000)) == 0) + return -ETIMEDOUT; + + /* Check if efx_mcdi_set_mode() switched us back to polled completions. + * In which case, poll for completions directly. If efx_mcdi_ev_cpl() + * completed the request first, then we'll just end up completing the + * request again, which is safe. + * + * We need an smp_rmb() to synchronise with efx_mcdi_mode_poll(), which + * wait_event_timeout() implicitly provides. + */ + if (mcdi->mode == MCDI_MODE_POLL) + return efx_mcdi_poll(efx); + + return 0; +} + +static bool efx_mcdi_complete(struct efx_mcdi_iface *mcdi) +{ + /* If the interface is RUNNING, then move to COMPLETED and wake any + * waiters. If the interface isn't in RUNNING then we've received a + * duplicate completion after we've already transitioned back to + * QUIESCENT. [A subsequent invocation would increment seqno, so would + * have failed the seqno check]. + */ + if (atomic_cmpxchg(&mcdi->state, + MCDI_STATE_RUNNING, + MCDI_STATE_COMPLETED) == MCDI_STATE_RUNNING) { + wake_up(&mcdi->wq); + return true; + } + + return false; +} + +static void efx_mcdi_release(struct efx_mcdi_iface *mcdi) +{ + atomic_set(&mcdi->state, MCDI_STATE_QUIESCENT); + wake_up(&mcdi->wq); +} + +static void efx_mcdi_ev_cpl(struct efx_nic *efx, unsigned int seqno, + unsigned int datalen, unsigned int errno) +{ + struct efx_mcdi_iface *mcdi = efx_mcdi(efx); + bool wake = false; + + spin_lock(&mcdi->iface_lock); + + if ((seqno ^ mcdi->seqno) & SEQ_MASK) { + if (mcdi->credits) + /* The request has been cancelled */ + --mcdi->credits; + else + EFX_ERR(efx, "MC response mismatch tx seq 0x%x rx " + "seq 0x%x\n", seqno, mcdi->seqno); + } else { + mcdi->resprc = errno; + mcdi->resplen = datalen; + + wake = true; + } + + spin_unlock(&mcdi->iface_lock); + + if (wake) + efx_mcdi_complete(mcdi); +} + +/* Issue the given command by writing the data into the shared memory PDU, + * ring the doorbell and wait for completion. Copyout the result. */ +int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, + const u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen, + size_t *outlen_actual) +{ + struct efx_mcdi_iface *mcdi = efx_mcdi(efx); + int rc; + BUG_ON(efx_nic_rev(efx) < EFX_REV_SIENA_A0); + + efx_mcdi_acquire(mcdi); + + /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */ + spin_lock_bh(&mcdi->iface_lock); + ++mcdi->seqno; + spin_unlock_bh(&mcdi->iface_lock); + + efx_mcdi_copyin(efx, cmd, inbuf, inlen); + + if (mcdi->mode == MCDI_MODE_POLL) + rc = efx_mcdi_poll(efx); + else + rc = efx_mcdi_await_completion(efx); + + if (rc != 0) { + /* Close the race with efx_mcdi_ev_cpl() executing just too late + * and completing a request we've just cancelled, by ensuring + * that the seqno check therein fails. + */ + spin_lock_bh(&mcdi->iface_lock); + ++mcdi->seqno; + ++mcdi->credits; + spin_unlock_bh(&mcdi->iface_lock); + + EFX_ERR(efx, "MC command 0x%x inlen %d mode %d timed out\n", + cmd, (int)inlen, mcdi->mode); + } else { + size_t resplen; + + /* At the very least we need a memory barrier here to ensure + * we pick up changes from efx_mcdi_ev_cpl(). Protect against + * a spurious efx_mcdi_ev_cpl() running concurrently by + * acquiring the iface_lock. */ + spin_lock_bh(&mcdi->iface_lock); + rc = -mcdi->resprc; + resplen = mcdi->resplen; + spin_unlock_bh(&mcdi->iface_lock); + + if (rc == 0) { + efx_mcdi_copyout(efx, outbuf, + min(outlen, mcdi->resplen + 3) & ~0x3); + if (outlen_actual != NULL) + *outlen_actual = resplen; + } else if (cmd == MC_CMD_REBOOT && rc == -EIO) + ; /* Don't reset if MC_CMD_REBOOT returns EIO */ + else if (rc == -EIO || rc == -EINTR) { + EFX_ERR(efx, "MC fatal error %d\n", -rc); + efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE); + } else + EFX_ERR(efx, "MC command 0x%x inlen %d failed rc=%d\n", + cmd, (int)inlen, -rc); + } + + efx_mcdi_release(mcdi); + return rc; +} + +void efx_mcdi_mode_poll(struct efx_nic *efx) +{ + struct efx_mcdi_iface *mcdi; + + if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) + return; + + mcdi = efx_mcdi(efx); + if (mcdi->mode == MCDI_MODE_POLL) + return; + + /* We can switch from event completion to polled completion, because + * mcdi requests are always completed in shared memory. We do this by + * switching the mode to POLL'd then completing the request. + * efx_mcdi_await_completion() will then call efx_mcdi_poll(). + * + * We need an smp_wmb() to synchronise with efx_mcdi_await_completion(), + * which efx_mcdi_complete() provides for us. + */ + mcdi->mode = MCDI_MODE_POLL; + + efx_mcdi_complete(mcdi); +} + +void efx_mcdi_mode_event(struct efx_nic *efx) +{ + struct efx_mcdi_iface *mcdi; + + if (efx_nic_rev(efx) < EFX_REV_SIENA_A0) + return; + + mcdi = efx_mcdi(efx); + + if (mcdi->mode == MCDI_MODE_EVENTS) + return; + + /* We can't switch from polled to event completion in the middle of a + * request, because the completion method is specified in the request. + * So acquire the interface to serialise the requestors. We don't need + * to acquire the iface_lock to change the mode here, but we do need a + * write memory barrier ensure that efx_mcdi_rpc() sees it, which + * efx_mcdi_acquire() provides. + */ + efx_mcdi_acquire(mcdi); + mcdi->mode = MCDI_MODE_EVENTS; + efx_mcdi_release(mcdi); +} + +static void efx_mcdi_ev_death(struct efx_nic *efx, int rc) +{ + struct efx_mcdi_iface *mcdi = efx_mcdi(efx); + + /* If there is an outstanding MCDI request, it has been terminated + * either by a BADASSERT or REBOOT event. If the mcdi interface is + * in polled mode, then do nothing because the MC reboot handler will + * set the header correctly. However, if the mcdi interface is waiting + * for a CMDDONE event it won't receive it [and since all MCDI events + * are sent to the same queue, we can't be racing with + * efx_mcdi_ev_cpl()] + * + * There's a race here with efx_mcdi_rpc(), because we might receive + * a REBOOT event *before* the request has been copied out. In polled + * mode (during startup) this is irrelevent, because efx_mcdi_complete() + * is ignored. In event mode, this condition is just an edge-case of + * receiving a REBOOT event after posting the MCDI request. Did the mc + * reboot before or after the copyout? The best we can do always is + * just return failure. + */ + spin_lock(&mcdi->iface_lock); + if (efx_mcdi_complete(mcdi)) { + if (mcdi->mode == MCDI_MODE_EVENTS) { + mcdi->resprc = rc; + mcdi->resplen = 0; + } + } else + /* Nobody was waiting for an MCDI request, so trigger a reset */ + efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE); + + spin_unlock(&mcdi->iface_lock); +} + +static unsigned int efx_mcdi_event_link_speed[] = { + [MCDI_EVENT_LINKCHANGE_SPEED_100M] = 100, + [MCDI_EVENT_LINKCHANGE_SPEED_1G] = 1000, + [MCDI_EVENT_LINKCHANGE_SPEED_10G] = 10000, +}; + + +static void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev) +{ + u32 flags, fcntl, speed, lpa; + + speed = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_SPEED); + EFX_BUG_ON_PARANOID(speed >= ARRAY_SIZE(efx_mcdi_event_link_speed)); + speed = efx_mcdi_event_link_speed[speed]; + + flags = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LINK_FLAGS); + fcntl = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_FCNTL); + lpa = EFX_QWORD_FIELD(*ev, MCDI_EVENT_LINKCHANGE_LP_CAP); + + /* efx->link_state is only modified by efx_mcdi_phy_get_link(), + * which is only run after flushing the event queues. Therefore, it + * is safe to modify the link state outside of the mac_lock here. + */ + efx_mcdi_phy_decode_link(efx, &efx->link_state, speed, flags, fcntl); + + efx_mcdi_phy_check_fcntl(efx, lpa); + + efx_link_status_changed(efx); +} + +static const char *sensor_names[] = { + [MC_CMD_SENSOR_CONTROLLER_TEMP] = "Controller temp. sensor", + [MC_CMD_SENSOR_PHY_COMMON_TEMP] = "PHY shared temp. sensor", + [MC_CMD_SENSOR_CONTROLLER_COOLING] = "Controller cooling", + [MC_CMD_SENSOR_PHY0_TEMP] = "PHY 0 temp. sensor", + [MC_CMD_SENSOR_PHY0_COOLING] = "PHY 0 cooling", + [MC_CMD_SENSOR_PHY1_TEMP] = "PHY 1 temp. sensor", + [MC_CMD_SENSOR_PHY1_COOLING] = "PHY 1 cooling", + [MC_CMD_SENSOR_IN_1V0] = "1.0V supply sensor", + [MC_CMD_SENSOR_IN_1V2] = "1.2V supply sensor", + [MC_CMD_SENSOR_IN_1V8] = "1.8V supply sensor", + [MC_CMD_SENSOR_IN_2V5] = "2.5V supply sensor", + [MC_CMD_SENSOR_IN_3V3] = "3.3V supply sensor", + [MC_CMD_SENSOR_IN_12V0] = "12V supply sensor" +}; + +static const char *sensor_status_names[] = { + [MC_CMD_SENSOR_STATE_OK] = "OK", + [MC_CMD_SENSOR_STATE_WARNING] = "Warning", + [MC_CMD_SENSOR_STATE_FATAL] = "Fatal", + [MC_CMD_SENSOR_STATE_BROKEN] = "Device failure", +}; + +static void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev) +{ + unsigned int monitor, state, value; + const char *name, *state_txt; + monitor = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR); + state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE); + value = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_VALUE); + /* Deal gracefully with the board having more drivers than we + * know about, but do not expect new sensor states. */ + name = (monitor >= ARRAY_SIZE(sensor_names)) + ? "No sensor name available" : + sensor_names[monitor]; + EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names)); + state_txt = sensor_status_names[state]; + + EFX_ERR(efx, "Sensor %d (%s) reports condition '%s' for raw value %d\n", + monitor, name, state_txt, value); +} + +/* Called from falcon_process_eventq for MCDI events */ +void efx_mcdi_process_event(struct efx_channel *channel, + efx_qword_t *event) +{ + struct efx_nic *efx = channel->efx; + int code = EFX_QWORD_FIELD(*event, MCDI_EVENT_CODE); + u32 data = EFX_QWORD_FIELD(*event, MCDI_EVENT_DATA); + + switch (code) { + case MCDI_EVENT_CODE_BADSSERT: + EFX_ERR(efx, "MC watchdog or assertion failure at 0x%x\n", data); + efx_mcdi_ev_death(efx, EINTR); + break; + + case MCDI_EVENT_CODE_PMNOTICE: + EFX_INFO(efx, "MCDI PM event.\n"); + break; + + case MCDI_EVENT_CODE_CMDDONE: + efx_mcdi_ev_cpl(efx, + MCDI_EVENT_FIELD(*event, CMDDONE_SEQ), + MCDI_EVENT_FIELD(*event, CMDDONE_DATALEN), + MCDI_EVENT_FIELD(*event, CMDDONE_ERRNO)); + break; + + case MCDI_EVENT_CODE_LINKCHANGE: + efx_mcdi_process_link_change(efx, event); + break; + case MCDI_EVENT_CODE_SENSOREVT: + efx_mcdi_sensor_event(efx, event); + break; + case MCDI_EVENT_CODE_SCHEDERR: + EFX_INFO(efx, "MC Scheduler error address=0x%x\n", data); + break; + case MCDI_EVENT_CODE_REBOOT: + EFX_INFO(efx, "MC Reboot\n"); + efx_mcdi_ev_death(efx, EIO); + break; + case MCDI_EVENT_CODE_MAC_STATS_DMA: + /* MAC stats are gather lazily. We can ignore this. */ + break; + + default: + EFX_ERR(efx, "Unknown MCDI event 0x%x\n", code); + } +} + +/************************************************************************** + * + * Specific request functions + * + ************************************************************************** + */ + +int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build) +{ + u8 outbuf[ALIGN(MC_CMD_GET_VERSION_V1_OUT_LEN, 4)]; + size_t outlength; + const __le16 *ver_words; + int rc; + + BUILD_BUG_ON(MC_CMD_GET_VERSION_IN_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, NULL, 0, + outbuf, sizeof(outbuf), &outlength); + if (rc) + goto fail; + + if (outlength == MC_CMD_GET_VERSION_V0_OUT_LEN) { + *version = 0; + *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE); + return 0; + } + + if (outlength < MC_CMD_GET_VERSION_V1_OUT_LEN) { + rc = -EMSGSIZE; + goto fail; + } + + ver_words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_OUT_VERSION); + *version = (((u64)le16_to_cpu(ver_words[0]) << 48) | + ((u64)le16_to_cpu(ver_words[1]) << 32) | + ((u64)le16_to_cpu(ver_words[2]) << 16) | + le16_to_cpu(ver_words[3])); + *build = MCDI_DWORD(outbuf, GET_VERSION_OUT_FIRMWARE); + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, + bool *was_attached) +{ + u8 inbuf[MC_CMD_DRV_ATTACH_IN_LEN]; + u8 outbuf[MC_CMD_DRV_ATTACH_OUT_LEN]; + size_t outlen; + int rc; + + MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_NEW_STATE, + driver_operating ? 1 : 0); + MCDI_SET_DWORD(inbuf, DRV_ATTACH_IN_UPDATE, 1); + + rc = efx_mcdi_rpc(efx, MC_CMD_DRV_ATTACH, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + if (outlen < MC_CMD_DRV_ATTACH_OUT_LEN) + goto fail; + + if (was_attached != NULL) + *was_attached = MCDI_DWORD(outbuf, DRV_ATTACH_OUT_OLD_STATE); + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, + u16 *fw_subtype_list) +{ + uint8_t outbuf[MC_CMD_GET_BOARD_CFG_OUT_LEN]; + size_t outlen; + int port_num = efx_port_num(efx); + int offset; + int rc; + + BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0, + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + + if (outlen < MC_CMD_GET_BOARD_CFG_OUT_LEN) { + rc = -EMSGSIZE; + goto fail; + } + + offset = (port_num) + ? MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST + : MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST; + if (mac_address) + memcpy(mac_address, outbuf + offset, ETH_ALEN); + if (fw_subtype_list) + memcpy(fw_subtype_list, + outbuf + MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST, + MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN); + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d len=%d\n", __func__, rc, (int)outlen); + + return rc; +} + +int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq) +{ + u8 inbuf[MC_CMD_LOG_CTRL_IN_LEN]; + u32 dest = 0; + int rc; + + if (uart) + dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_UART; + if (evq) + dest |= MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ; + + MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST, dest); + MCDI_SET_DWORD(inbuf, LOG_CTRL_IN_LOG_DEST_EVQ, dest_evq); + + BUILD_BUG_ON(MC_CMD_LOG_CTRL_OUT_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf), + NULL, 0, NULL); + if (rc) + goto fail; + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out) +{ + u8 outbuf[MC_CMD_NVRAM_TYPES_OUT_LEN]; + size_t outlen; + int rc; + + BUILD_BUG_ON(MC_CMD_NVRAM_TYPES_IN_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_TYPES, NULL, 0, + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + if (outlen < MC_CMD_NVRAM_TYPES_OUT_LEN) + goto fail; + + *nvram_types_out = MCDI_DWORD(outbuf, NVRAM_TYPES_OUT_TYPES); + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", + __func__, rc); + return rc; +} + +int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, + size_t *size_out, size_t *erase_size_out, + bool *protected_out) +{ + u8 inbuf[MC_CMD_NVRAM_INFO_IN_LEN]; + u8 outbuf[MC_CMD_NVRAM_INFO_OUT_LEN]; + size_t outlen; + int rc; + + MCDI_SET_DWORD(inbuf, NVRAM_INFO_IN_TYPE, type); + + rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_INFO, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + if (outlen < MC_CMD_NVRAM_INFO_OUT_LEN) + goto fail; + + *size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_SIZE); + *erase_size_out = MCDI_DWORD(outbuf, NVRAM_INFO_OUT_ERASESIZE); + *protected_out = !!(MCDI_DWORD(outbuf, NVRAM_INFO_OUT_FLAGS) & + (1 << MC_CMD_NVRAM_PROTECTED_LBN)); + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type) +{ + u8 inbuf[MC_CMD_NVRAM_UPDATE_START_IN_LEN]; + int rc; + + MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type); + + BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf), + NULL, 0, NULL); + if (rc) + goto fail; + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, + loff_t offset, u8 *buffer, size_t length) +{ + u8 inbuf[MC_CMD_NVRAM_READ_IN_LEN]; + u8 outbuf[MC_CMD_NVRAM_READ_OUT_LEN(length)]; + size_t outlen; + int rc; + + MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type); + MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset); + MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length); + + rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + + memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length); + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, + loff_t offset, const u8 *buffer, size_t length) +{ + u8 inbuf[MC_CMD_NVRAM_WRITE_IN_LEN(length)]; + int rc; + + MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type); + MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset); + MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length); + memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length); + + BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, sizeof(inbuf), + NULL, 0, NULL); + if (rc) + goto fail; + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, + loff_t offset, size_t length) +{ + u8 inbuf[MC_CMD_NVRAM_ERASE_IN_LEN]; + int rc; + + MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type); + MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset); + MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length); + + BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf), + NULL, 0, NULL); + if (rc) + goto fail; + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type) +{ + u8 inbuf[MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN]; + int rc; + + MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type); + + BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf), + NULL, 0, NULL); + if (rc) + goto fail; + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_handle_assertion(struct efx_nic *efx) +{ + union { + u8 asserts[MC_CMD_GET_ASSERTS_IN_LEN]; + u8 reboot[MC_CMD_REBOOT_IN_LEN]; + } inbuf; + u8 assertion[MC_CMD_GET_ASSERTS_OUT_LEN]; + unsigned int flags, index, ofst; + const char *reason; + size_t outlen; + int retry; + int rc; + + /* Check if the MC is in the assertion handler, retrying twice. Once + * because a boot-time assertion might cause this command to fail + * with EINTR. And once again because GET_ASSERTS can race with + * MC_CMD_REBOOT running on the other port. */ + retry = 2; + do { + MCDI_SET_DWORD(inbuf.asserts, GET_ASSERTS_IN_CLEAR, 0); + rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS, + inbuf.asserts, MC_CMD_GET_ASSERTS_IN_LEN, + assertion, sizeof(assertion), &outlen); + } while ((rc == -EINTR || rc == -EIO) && retry-- > 0); + + if (rc) + return rc; + if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN) + return -EINVAL; + + flags = MCDI_DWORD(assertion, GET_ASSERTS_OUT_GLOBAL_FLAGS); + if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) + return 0; + + /* Reset the hardware atomically such that only one port with succeed. + * This command will succeed if a reboot is no longer required (because + * the other port did it first), but fail with EIO if it succeeds. + */ + BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); + MCDI_SET_DWORD(inbuf.reboot, REBOOT_IN_FLAGS, + MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION); + efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf.reboot, MC_CMD_REBOOT_IN_LEN, + NULL, 0, NULL); + + /* Print out the assertion */ + reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) + ? "system-level assertion" + : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) + ? "thread-level assertion" + : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) + ? "watchdog reset" + : "unknown assertion"; + EFX_ERR(efx, "MCPU %s at PC = 0x%.8x in thread 0x%.8x\n", reason, + MCDI_DWORD(assertion, GET_ASSERTS_OUT_SAVED_PC_OFFS), + MCDI_DWORD(assertion, GET_ASSERTS_OUT_THREAD_OFFS)); + + /* Print out the registers */ + ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; + for (index = 1; index < 32; index++) { + EFX_ERR(efx, "R%.2d (?): 0x%.8x\n", index, + MCDI_DWORD2(assertion, ofst)); + ofst += sizeof(efx_dword_t); + } + + return 0; +} + +void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode) +{ + u8 inbuf[MC_CMD_SET_ID_LED_IN_LEN]; + int rc; + + BUILD_BUG_ON(EFX_LED_OFF != MC_CMD_LED_OFF); + BUILD_BUG_ON(EFX_LED_ON != MC_CMD_LED_ON); + BUILD_BUG_ON(EFX_LED_DEFAULT != MC_CMD_LED_DEFAULT); + + BUILD_BUG_ON(MC_CMD_SET_ID_LED_OUT_LEN != 0); + + MCDI_SET_DWORD(inbuf, SET_ID_LED_IN_STATE, mode); + + rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf), + NULL, 0, NULL); + if (rc) + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); +} + +int efx_mcdi_reset_port(struct efx_nic *efx) +{ + int rc = efx_mcdi_rpc(efx, MC_CMD_PORT_RESET, NULL, 0, NULL, 0, NULL); + if (rc) + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_reset_mc(struct efx_nic *efx) +{ + u8 inbuf[MC_CMD_REBOOT_IN_LEN]; + int rc; + + BUILD_BUG_ON(MC_CMD_REBOOT_OUT_LEN != 0); + MCDI_SET_DWORD(inbuf, REBOOT_IN_FLAGS, 0); + rc = efx_mcdi_rpc(efx, MC_CMD_REBOOT, inbuf, sizeof(inbuf), + NULL, 0, NULL); + /* White is black, and up is down */ + if (rc == -EIO) + return 0; + if (rc == 0) + rc = -EIO; + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, + const u8 *mac, int *id_out) +{ + u8 inbuf[MC_CMD_WOL_FILTER_SET_IN_LEN]; + u8 outbuf[MC_CMD_WOL_FILTER_SET_OUT_LEN]; + size_t outlen; + int rc; + + MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type); + MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE, + MC_CMD_FILTER_MODE_SIMPLE); + memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN); + + rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + + if (outlen < MC_CMD_WOL_FILTER_SET_OUT_LEN) { + rc = -EMSGSIZE; + goto fail; + } + + *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_SET_OUT_FILTER_ID); + + return 0; + +fail: + *id_out = -1; + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; + +} + + +int +efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, const u8 *mac, int *id_out) +{ + return efx_mcdi_wol_filter_set(efx, MC_CMD_WOL_TYPE_MAGIC, mac, id_out); +} + + +int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out) +{ + u8 outbuf[MC_CMD_WOL_FILTER_GET_OUT_LEN]; + size_t outlen; + int rc; + + rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_GET, NULL, 0, + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + + if (outlen < MC_CMD_WOL_FILTER_GET_OUT_LEN) { + rc = -EMSGSIZE; + goto fail; + } + + *id_out = (int)MCDI_DWORD(outbuf, WOL_FILTER_GET_OUT_FILTER_ID); + + return 0; + +fail: + *id_out = -1; + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + + +int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id) +{ + u8 inbuf[MC_CMD_WOL_FILTER_REMOVE_IN_LEN]; + int rc; + + MCDI_SET_DWORD(inbuf, WOL_FILTER_REMOVE_IN_FILTER_ID, (u32)id); + + rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf), + NULL, 0, NULL); + if (rc) + goto fail; + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + + +int efx_mcdi_wol_filter_reset(struct efx_nic *efx) +{ + int rc; + + rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL); + if (rc) + goto fail; + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h new file mode 100644 index 00000000000..de916728c2e --- /dev/null +++ b/drivers/net/sfc/mcdi.h @@ -0,0 +1,130 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2008-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#ifndef EFX_MCDI_H +#define EFX_MCDI_H + +/** + * enum efx_mcdi_state + * @MCDI_STATE_QUIESCENT: No pending MCDI requests. If the caller holds the + * mcdi_lock then they are able to move to MCDI_STATE_RUNNING + * @MCDI_STATE_RUNNING: There is an MCDI request pending. Only the thread that + * moved into this state is allowed to move out of it. + * @MCDI_STATE_COMPLETED: An MCDI request has completed, but the owning thread + * has not yet consumed the result. For all other threads, equivalent to + * MCDI_STATE_RUNNING. + */ +enum efx_mcdi_state { + MCDI_STATE_QUIESCENT, + MCDI_STATE_RUNNING, + MCDI_STATE_COMPLETED, +}; + +enum efx_mcdi_mode { + MCDI_MODE_POLL, + MCDI_MODE_EVENTS, +}; + +/** + * struct efx_mcdi_iface + * @state: Interface state. Waited for by mcdi_wq. + * @wq: Wait queue for threads waiting for state != STATE_RUNNING + * @iface_lock: Protects @credits, @seqno, @resprc, @resplen + * @mode: Poll for mcdi completion, or wait for an mcdi_event. + * Serialised by @lock + * @seqno: The next sequence number to use for mcdi requests. + * Serialised by @lock + * @credits: Number of spurious MCDI completion events allowed before we + * trigger a fatal error. Protected by @lock + * @resprc: Returned MCDI completion + * @resplen: Returned payload length + */ +struct efx_mcdi_iface { + atomic_t state; + wait_queue_head_t wq; + spinlock_t iface_lock; + enum efx_mcdi_mode mode; + unsigned int credits; + unsigned int seqno; + unsigned int resprc; + size_t resplen; +}; + +extern void efx_mcdi_init(struct efx_nic *efx); + +extern int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const u8 *inbuf, + size_t inlen, u8 *outbuf, size_t outlen, + size_t *outlen_actual); + +extern int efx_mcdi_poll_reboot(struct efx_nic *efx); +extern void efx_mcdi_mode_poll(struct efx_nic *efx); +extern void efx_mcdi_mode_event(struct efx_nic *efx); + +extern void efx_mcdi_process_event(struct efx_channel *channel, + efx_qword_t *event); + +#define MCDI_PTR2(_buf, _ofst) \ + (((u8 *)_buf) + _ofst) +#define MCDI_SET_DWORD2(_buf, _ofst, _value) \ + EFX_POPULATE_DWORD_1(*((efx_dword_t *)MCDI_PTR2(_buf, _ofst)), \ + EFX_DWORD_0, _value) +#define MCDI_DWORD2(_buf, _ofst) \ + EFX_DWORD_FIELD(*((efx_dword_t *)MCDI_PTR2(_buf, _ofst)), \ + EFX_DWORD_0) +#define MCDI_QWORD2(_buf, _ofst) \ + EFX_QWORD_FIELD64(*((efx_qword_t *)MCDI_PTR2(_buf, _ofst)), \ + EFX_QWORD_0) + +#define MCDI_PTR(_buf, _ofst) \ + MCDI_PTR2(_buf, MC_CMD_ ## _ofst ## _OFST) +#define MCDI_SET_DWORD(_buf, _ofst, _value) \ + MCDI_SET_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST, _value) +#define MCDI_DWORD(_buf, _ofst) \ + MCDI_DWORD2(_buf, MC_CMD_ ## _ofst ## _OFST) +#define MCDI_QWORD(_buf, _ofst) \ + MCDI_QWORD2(_buf, MC_CMD_ ## _ofst ## _OFST) + +#define MCDI_EVENT_FIELD(_ev, _field) \ + EFX_QWORD_FIELD(_ev, MCDI_EVENT_ ## _field) + +extern int efx_mcdi_fwver(struct efx_nic *efx, u64 *version, u32 *build); +extern int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, + bool *was_attached_out); +extern int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, + u16 *fw_subtype_list); +extern int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, + u32 dest_evq); +extern int efx_mcdi_nvram_types(struct efx_nic *efx, u32 *nvram_types_out); +extern int efx_mcdi_nvram_info(struct efx_nic *efx, unsigned int type, + size_t *size_out, size_t *erase_size_out, + bool *protected_out); +extern int efx_mcdi_nvram_update_start(struct efx_nic *efx, + unsigned int type); +extern int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, + loff_t offset, u8 *buffer, size_t length); +extern int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, + loff_t offset, const u8 *buffer, + size_t length); +extern int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, + loff_t offset, size_t length); +extern int efx_mcdi_nvram_update_finish(struct efx_nic *efx, + unsigned int type); +extern int efx_mcdi_handle_assertion(struct efx_nic *efx); +extern void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode); +extern int efx_mcdi_reset_port(struct efx_nic *efx); +extern int efx_mcdi_reset_mc(struct efx_nic *efx); +extern int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, + const u8 *mac, int *id_out); +extern int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, + const u8 *mac, int *id_out); +extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out); +extern int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id); +extern int efx_mcdi_wol_filter_reset(struct efx_nic *efx); + +#endif /* EFX_MCDI_H */ diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c new file mode 100644 index 00000000000..06d24a1e412 --- /dev/null +++ b/drivers/net/sfc/mcdi_mac.c @@ -0,0 +1,152 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include "net_driver.h" +#include "efx.h" +#include "mac.h" +#include "mcdi.h" +#include "mcdi_pcol.h" + +static int efx_mcdi_set_mac(struct efx_nic *efx) +{ + u32 reject, fcntl; + u8 cmdbytes[MC_CMD_SET_MAC_IN_LEN]; + + memcpy(cmdbytes + MC_CMD_SET_MAC_IN_ADDR_OFST, + efx->net_dev->dev_addr, ETH_ALEN); + + MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU, + EFX_MAX_FRAME_LEN(efx->net_dev->mtu)); + MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_DRAIN, 0); + + /* The MCDI command provides for controlling accept/reject + * of broadcast packets too, but the driver doesn't currently + * expose this. */ + reject = (efx->promiscuous) ? 0 : + (1 << MC_CMD_SET_MAC_IN_REJECT_UNCST_LBN); + MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_REJECT, reject); + + switch (efx->wanted_fc) { + case EFX_FC_RX | EFX_FC_TX: + fcntl = MC_CMD_FCNTL_BIDIR; + break; + case EFX_FC_RX: + fcntl = MC_CMD_FCNTL_RESPOND; + break; + default: + fcntl = MC_CMD_FCNTL_OFF; + break; + } + if (efx->wanted_fc & EFX_FC_AUTO) + fcntl = MC_CMD_FCNTL_AUTO; + + MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_FCNTL, fcntl); + + return efx_mcdi_rpc(efx, MC_CMD_SET_MAC, cmdbytes, sizeof(cmdbytes), + NULL, 0, NULL); +} + +static int efx_mcdi_get_mac_faults(struct efx_nic *efx, u32 *faults) +{ + u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; + size_t outlength; + int rc; + + BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, + outbuf, sizeof(outbuf), &outlength); + if (rc) + goto fail; + + *faults = MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT); + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", + __func__, rc); + return rc; +} + +int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr, + u32 dma_len, int enable, int clear) +{ + u8 inbuf[MC_CMD_MAC_STATS_IN_LEN]; + int rc; + efx_dword_t *cmd_ptr; + int period = 1000; + u32 addr_hi; + u32 addr_lo; + + BUILD_BUG_ON(MC_CMD_MAC_STATS_OUT_LEN != 0); + + addr_lo = ((u64)dma_addr) >> 0; + addr_hi = ((u64)dma_addr) >> 32; + + MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_LO, addr_lo); + MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_ADDR_HI, addr_hi); + cmd_ptr = (efx_dword_t *)MCDI_PTR(inbuf, MAC_STATS_IN_CMD); + if (enable) + EFX_POPULATE_DWORD_6(*cmd_ptr, + MC_CMD_MAC_STATS_CMD_DMA, 1, + MC_CMD_MAC_STATS_CMD_CLEAR, clear, + MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1, + MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 1, + MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0, + MC_CMD_MAC_STATS_CMD_PERIOD_MS, period); + else + EFX_POPULATE_DWORD_5(*cmd_ptr, + MC_CMD_MAC_STATS_CMD_DMA, 0, + MC_CMD_MAC_STATS_CMD_CLEAR, clear, + MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE, 1, + MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE, 0, + MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR, 0); + MCDI_SET_DWORD(inbuf, MAC_STATS_IN_DMA_LEN, dma_len); + + rc = efx_mcdi_rpc(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf), + NULL, 0, NULL); + if (rc) + goto fail; + + return 0; + +fail: + EFX_ERR(efx, "%s: %s failed rc=%d\n", + __func__, enable ? "enable" : "disable", rc); + return rc; +} + +static int efx_mcdi_mac_reconfigure(struct efx_nic *efx) +{ + int rc; + + rc = efx_mcdi_set_mac(efx); + if (rc != 0) + return rc; + + /* Restore the multicast hash registers. */ + efx->type->push_multicast_hash(efx); + + return 0; +} + + +static bool efx_mcdi_mac_check_fault(struct efx_nic *efx) +{ + u32 faults; + int rc = efx_mcdi_get_mac_faults(efx, &faults); + return (rc != 0) || (faults != 0); +} + + +struct efx_mac_operations efx_mcdi_mac_operations = { + .reconfigure = efx_mcdi_mac_reconfigure, + .update_stats = efx_port_dummy_op_void, + .check_fault = efx_mcdi_mac_check_fault, +}; diff --git a/drivers/net/sfc/mcdi_pcol.h b/drivers/net/sfc/mcdi_pcol.h new file mode 100644 index 00000000000..2a85360a46f --- /dev/null +++ b/drivers/net/sfc/mcdi_pcol.h @@ -0,0 +1,1578 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + + +#ifndef MCDI_PCOL_H +#define MCDI_PCOL_H + +/* Values to be written into FMCR_CZ_RESET_STATE_REG to control boot. */ +/* Power-on reset state */ +#define MC_FW_STATE_POR (1) +/* If this is set in MC_RESET_STATE_REG then it should be + * possible to jump into IMEM without loading code from flash. */ +#define MC_FW_WARM_BOOT_OK (2) +/* The MC main image has started to boot. */ +#define MC_FW_STATE_BOOTING (4) +/* The Scheduler has started. */ +#define MC_FW_STATE_SCHED (8) + +/* Values to be written to the per-port status dword in shared + * memory on reboot and assert */ +#define MC_STATUS_DWORD_REBOOT (0xb007b007) +#define MC_STATUS_DWORD_ASSERT (0xdeaddead) + +/* The current version of the MCDI protocol. + * + * Note that the ROM burnt into the card only talks V0, so at the very + * least every driver must support version 0 and MCDI_PCOL_VERSION + */ +#define MCDI_PCOL_VERSION 1 + +/** + * MCDI version 1 + * + * Each MCDI request starts with an MCDI_HEADER, which is a 32byte + * structure, filled in by the client. + * + * 0 7 8 16 20 22 23 24 31 + * | CODE | R | LEN | SEQ | Rsvd | E | R | XFLAGS | + * | | | + * | | \--- Response + * | \------- Error + * \------------------------------ Resync (always set) + * + * The client writes it's request into MC shared memory, and rings the + * doorbell. Each request is completed by either by the MC writting + * back into shared memory, or by writting out an event. + * + * All MCDI commands support completion by shared memory response. Each + * request may also contain additional data (accounted for by HEADER.LEN), + * and some response's may also contain additional data (again, accounted + * for by HEADER.LEN). + * + * Some MCDI commands support completion by event, in which any associated + * response data is included in the event. + * + * The protocol requires one response to be delivered for every request, a + * request should not be sent unless the response for the previous request + * has been received (either by polling shared memory, or by receiving + * an event). + */ + +/** Request/Response structure */ +#define MCDI_HEADER_OFST 0 +#define MCDI_HEADER_CODE_LBN 0 +#define MCDI_HEADER_CODE_WIDTH 7 +#define MCDI_HEADER_RESYNC_LBN 7 +#define MCDI_HEADER_RESYNC_WIDTH 1 +#define MCDI_HEADER_DATALEN_LBN 8 +#define MCDI_HEADER_DATALEN_WIDTH 8 +#define MCDI_HEADER_SEQ_LBN 16 +#define MCDI_HEADER_RSVD_LBN 20 +#define MCDI_HEADER_RSVD_WIDTH 2 +#define MCDI_HEADER_SEQ_WIDTH 4 +#define MCDI_HEADER_ERROR_LBN 22 +#define MCDI_HEADER_ERROR_WIDTH 1 +#define MCDI_HEADER_RESPONSE_LBN 23 +#define MCDI_HEADER_RESPONSE_WIDTH 1 +#define MCDI_HEADER_XFLAGS_LBN 24 +#define MCDI_HEADER_XFLAGS_WIDTH 8 +/* Request response using event */ +#define MCDI_HEADER_XFLAGS_EVREQ 0x01 + +/* Maximum number of payload bytes */ +#define MCDI_CTL_SDU_LEN_MAX 0xfc + +/* The MC can generate events for two reasons: + * - To complete a shared memory request if XFLAGS_EVREQ was set + * - As a notification (link state, i2c event), controlled + * via MC_CMD_LOG_CTRL + * + * Both events share a common structure: + * + * 0 32 33 36 44 52 60 + * | Data | Cont | Level | Src | Code | Rsvd | + * | + * \ There is another event pending in this notification + * + * If Code==CMDDONE, then the fields are further interpreted as: + * + * - LEVEL==INFO Command succeded + * - LEVEL==ERR Command failed + * + * 0 8 16 24 32 + * | Seq | Datalen | Errno | Rsvd | + * + * These fields are taken directly out of the standard MCDI header, i.e., + * LEVEL==ERR, Datalen == 0 => Reboot + * + * Events can be squirted out of the UART (using LOG_CTRL) without a + * MCDI header. An event can be distinguished from a MCDI response by + * examining the first byte which is 0xc0. This corresponds to the + * non-existent MCDI command MC_CMD_DEBUG_LOG. + * + * 0 7 8 + * | command | Resync | = 0xc0 + * + * Since the event is written in big-endian byte order, this works + * providing bits 56-63 of the event are 0xc0. + * + * 56 60 63 + * | Rsvd | Code | = 0xc0 + * + * Which means for convenience the event code is 0xc for all MC + * generated events. + */ +#define FSE_AZ_EV_CODE_MCDI_EVRESPONSE 0xc + +#define MCDI_EVENT_DATA_LBN 0 +#define MCDI_EVENT_DATA_WIDTH 32 +#define MCDI_EVENT_CONT_LBN 32 +#define MCDI_EVENT_CONT_WIDTH 1 +#define MCDI_EVENT_LEVEL_LBN 33 +#define MCDI_EVENT_LEVEL_WIDTH 3 +#define MCDI_EVENT_LEVEL_INFO (0) +#define MCDI_EVENT_LEVEL_WARN (1) +#define MCDI_EVENT_LEVEL_ERR (2) +#define MCDI_EVENT_LEVEL_FATAL (3) +#define MCDI_EVENT_SRC_LBN 36 +#define MCDI_EVENT_SRC_WIDTH 8 +#define MCDI_EVENT_CODE_LBN 44 +#define MCDI_EVENT_CODE_WIDTH 8 +#define MCDI_EVENT_CODE_BADSSERT (1) +#define MCDI_EVENT_CODE_PMNOTICE (2) +#define MCDI_EVENT_CODE_CMDDONE (3) +#define MCDI_EVENT_CMDDONE_SEQ_LBN 0 +#define MCDI_EVENT_CMDDONE_SEQ_WIDTH 8 +#define MCDI_EVENT_CMDDONE_DATALEN_LBN 8 +#define MCDI_EVENT_CMDDONE_DATALEN_WIDTH 8 +#define MCDI_EVENT_CMDDONE_ERRNO_LBN 16 +#define MCDI_EVENT_CMDDONE_ERRNO_WIDTH 8 +#define MCDI_EVENT_CODE_LINKCHANGE (4) +#define MCDI_EVENT_LINKCHANGE_LP_CAP_LBN 0 +#define MCDI_EVENT_LINKCHANGE_LP_CAP_WIDTH 16 +#define MCDI_EVENT_LINKCHANGE_SPEED_LBN 16 +#define MCDI_EVENT_LINKCHANGE_SPEED_WIDTH 4 +#define MCDI_EVENT_LINKCHANGE_SPEED_100M 1 +#define MCDI_EVENT_LINKCHANGE_SPEED_1G 2 +#define MCDI_EVENT_LINKCHANGE_SPEED_10G 3 +#define MCDI_EVENT_LINKCHANGE_FCNTL_LBN 20 +#define MCDI_EVENT_LINKCHANGE_FCNTL_WIDTH 4 +#define MCDI_EVENT_LINKCHANGE_LINK_FLAGS_LBN 24 +#define MCDI_EVENT_LINKCHANGE_LINK_FLAGS_WIDTH 8 +#define MCDI_EVENT_CODE_SENSOREVT (5) +#define MCDI_EVENT_SENSOREVT_MONITOR_LBN 0 +#define MCDI_EVENT_SENSOREVT_MONITOR_WIDTH 8 +#define MCDI_EVENT_SENSOREVT_STATE_LBN 8 +#define MCDI_EVENT_SENSOREVT_STATE_WIDTH 8 +#define MCDI_EVENT_SENSOREVT_VALUE_LBN 16 +#define MCDI_EVENT_SENSOREVT_VALUE_WIDTH 16 +#define MCDI_EVENT_CODE_SCHEDERR (6) +#define MCDI_EVENT_CODE_REBOOT (7) +#define MCDI_EVENT_CODE_MAC_STATS_DMA (8) +#define MCDI_EVENT_MAC_STATS_DMA_GENERATION_LBN 0 +#define MCDI_EVENT_MAC_STATS_DMA_GENERATION_WIDTH 32 + +/* Non-existent command target */ +#define MC_CMD_ERR_ENOENT 2 +/* assert() has killed the MC */ +#define MC_CMD_ERR_EINTR 4 +/* Caller does not hold required locks */ +#define MC_CMD_ERR_EACCES 13 +/* Resource is currently unavailable (e.g. lock contention) */ +#define MC_CMD_ERR_EBUSY 16 +/* Invalid argument to target */ +#define MC_CMD_ERR_EINVAL 22 +/* Non-recursive resource is already acquired */ +#define MC_CMD_ERR_EDEADLK 35 +/* Operation not implemented */ +#define MC_CMD_ERR_ENOSYS 38 +/* Operation timed out */ +#define MC_CMD_ERR_ETIME 62 + +#define MC_CMD_ERR_CODE_OFST 0 + + +/* MC_CMD_READ32: (debug, variadic out) + * Read multiple 32byte words from MC memory + */ +#define MC_CMD_READ32 0x01 +#define MC_CMD_READ32_IN_LEN 8 +#define MC_CMD_READ32_IN_ADDR_OFST 0 +#define MC_CMD_READ32_IN_NUMWORDS_OFST 4 +#define MC_CMD_READ32_OUT_LEN(_numwords) \ + (4 * (_numwords)) +#define MC_CMD_READ32_OUT_BUFFER_OFST 0 + +/* MC_CMD_WRITE32: (debug, variadic in) + * Write multiple 32byte words to MC memory + */ +#define MC_CMD_WRITE32 0x02 +#define MC_CMD_WRITE32_IN_LEN(_numwords) (((_numwords) * 4) + 4) +#define MC_CMD_WRITE32_IN_ADDR_OFST 0 +#define MC_CMD_WRITE32_IN_BUFFER_OFST 4 +#define MC_CMD_WRITE32_OUT_LEN 0 + +/* MC_CMD_COPYCODE: (debug) + * Copy MC code between two locations and jump + */ +#define MC_CMD_COPYCODE 0x03 +#define MC_CMD_COPYCODE_IN_LEN 16 +#define MC_CMD_COPYCODE_IN_SRC_ADDR_OFST 0 +#define MC_CMD_COPYCODE_IN_DEST_ADDR_OFST 4 +#define MC_CMD_COPYCODE_IN_NUMWORDS_OFST 8 +#define MC_CMD_COPYCODE_IN_JUMP_OFST 12 +/* Control should return to the caller rather than jumping */ +#define MC_CMD_COPYCODE_JUMP_NONE 1 +#define MC_CMD_COPYCODE_OUT_LEN 0 + +/* MC_CMD_SET_FUNC: (debug) + * Select function for function-specific commands. + */ +#define MC_CMD_SET_FUNC 0x04 +#define MC_CMD_SET_FUNC_IN_LEN 4 +#define MC_CMD_SET_FUNC_IN_FUNC_OFST 0 +#define MC_CMD_SET_FUNC_OUT_LEN 0 + +/* MC_CMD_GET_BOOT_STATUS: + * Get the instruction address from which the MC booted. + */ +#define MC_CMD_GET_BOOT_STATUS 0x05 +#define MC_CMD_GET_BOOT_STATUS_IN_LEN 0 +#define MC_CMD_GET_BOOT_STATUS_OUT_LEN 8 +#define MC_CMD_GET_BOOT_STATUS_OUT_BOOT_OFFSET_OFST 0 +#define MC_CMD_GET_BOOT_STATUS_OUT_FLAGS_OFST 4 +/* Reboot caused by watchdog */ +#define MC_CMD_GET_BOOT_STATUS_FLAGS_WATCHDOG_LBN (0) +#define MC_CMD_GET_BOOT_STATUS_FLAGS_WATCHDOG_WIDTH (1) +/* MC booted from primary flash partition */ +#define MC_CMD_GET_BOOT_STATUS_FLAGS_PRIMARY_LBN (1) +#define MC_CMD_GET_BOOT_STATUS_FLAGS_PRIMARY_WIDTH (1) +/* MC booted from backup flash partition */ +#define MC_CMD_GET_BOOT_STATUS_FLAGS_BACKUP_LBN (2) +#define MC_CMD_GET_BOOT_STATUS_FLAGS_BACKUP_WIDTH (1) + +/* MC_CMD_GET_ASSERTS: (debug, variadic out) + * Get (and optionally clear) the current assertion status. + * + * Only OUT.GLOBAL_FLAGS is guaranteed to exist in the completion + * payload. The other fields will only be present if + * OUT.GLOBAL_FLAGS != NO_FAILS + */ +#define MC_CMD_GET_ASSERTS 0x06 +#define MC_CMD_GET_ASSERTS_IN_LEN 4 +#define MC_CMD_GET_ASSERTS_IN_CLEAR_OFST 0 +#define MC_CMD_GET_ASSERTS_OUT_LEN 140 +/* Assertion status flag */ +#define MC_CMD_GET_ASSERTS_OUT_GLOBAL_FLAGS_OFST 0 +/*! No assertions have failed. */ +#define MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS 1 +/*! A system-level assertion has failed. */ +#define MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL 2 +/*! A thread-level assertion has failed. */ +#define MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL 3 +/*! The system was reset by the watchdog. */ +#define MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED 4 +/* Failing PC value */ +#define MC_CMD_GET_ASSERTS_OUT_SAVED_PC_OFFS_OFST 4 +/* Saved GP regs */ +#define MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST 8 +#define MC_CMD_GET_ASSERTS_OUT_GP_REGS_LEN 124 +/* Failing thread address */ +#define MC_CMD_GET_ASSERTS_OUT_THREAD_OFFS_OFST 132 + +/* MC_CMD_LOG_CTRL: + * Determine the output stream for various events and messages + */ +#define MC_CMD_LOG_CTRL 0x07 +#define MC_CMD_LOG_CTRL_IN_LEN 8 +#define MC_CMD_LOG_CTRL_IN_LOG_DEST_OFST 0 +#define MC_CMD_LOG_CTRL_IN_LOG_DEST_UART (1) +#define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ (2) +#define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ_OFST 4 +#define MC_CMD_LOG_CTRL_OUT_LEN 0 + +/* MC_CMD_GET_VERSION: + * Get version information about the MC firmware + */ +#define MC_CMD_GET_VERSION 0x08 +#define MC_CMD_GET_VERSION_IN_LEN 0 +#define MC_CMD_GET_VERSION_V0_OUT_LEN 4 +#define MC_CMD_GET_VERSION_V1_OUT_LEN 32 +#define MC_CMD_GET_VERSION_OUT_FIRMWARE_OFST 0 +/* Reserved version number to indicate "any" version. */ +#define MC_CMD_GET_VERSION_OUT_FIRMWARE_ANY 0xffffffff +/* The version response of a boot ROM awaiting rescue */ +#define MC_CMD_GET_VERSION_OUT_FIRMWARE_BOOTROM 0xb0070000 +#define MC_CMD_GET_VERSION_V1_OUT_PCOL_OFST 4 +/* 128bit mask of functions supported by the current firmware */ +#define MC_CMD_GET_VERSION_V1_OUT_SUPPORTED_FUNCS_OFST 8 +/* The command set exported by the boot ROM (MCDI v0) */ +#define MC_CMD_GET_VERSION_V0_SUPPORTED_FUNCS { \ + (1 << MC_CMD_READ32) | \ + (1 << MC_CMD_WRITE32) | \ + (1 << MC_CMD_COPYCODE) | \ + (1 << MC_CMD_GET_VERSION), \ + 0, 0, 0 } +#define MC_CMD_GET_VERSION_OUT_VERSION_OFST 24 + +/* Vectors in the boot ROM */ +/* Point to the copycode entry point. */ +#define MC_BOOTROM_COPYCODE_VEC (0x7f4) +/* Points to the recovery mode entry point. */ +#define MC_BOOTROM_NOFLASH_VEC (0x7f8) + +/* Test execution limits */ +#define MC_TESTEXEC_VARIANT_COUNT 16 +#define MC_TESTEXEC_RESULT_COUNT 7 + +/* MC_CMD_SET_TESTVARS: (debug, variadic in) + * Write variant words for test. + * + * The user supplies a bitmap of the variants they wish to set. + * They must ensure that IN.LEN >= 4 + 4 * ffs(BITMAP) + */ +#define MC_CMD_SET_TESTVARS 0x09 +#define MC_CMD_SET_TESTVARS_IN_LEN(_numwords) \ + (4 + 4*(_numwords)) +#define MC_CMD_SET_TESTVARS_IN_ARGS_BITMAP_OFST 0 +/* Up to MC_TESTEXEC_VARIANT_COUNT of 32byte words start here */ +#define MC_CMD_SET_TESTVARS_IN_ARGS_BUFFER_OFST 4 +#define MC_CMD_SET_TESTVARS_OUT_LEN 0 + +/* MC_CMD_GET_TESTRCS: (debug, variadic out) + * Return result words from test. + */ +#define MC_CMD_GET_TESTRCS 0x0a +#define MC_CMD_GET_TESTRCS_IN_LEN 4 +#define MC_CMD_GET_TESTRCS_IN_NUMWORDS_OFST 0 +#define MC_CMD_GET_TESTRCS_OUT_LEN(_numwords) \ + (4 * (_numwords)) +#define MC_CMD_GET_TESTRCS_OUT_BUFFER_OFST 0 + +/* MC_CMD_RUN_TEST: (debug) + * Run the test exported by this firmware image + */ +#define MC_CMD_RUN_TEST 0x0b +#define MC_CMD_RUN_TEST_IN_LEN 0 +#define MC_CMD_RUN_TEST_OUT_LEN 0 + +/* MC_CMD_CSR_READ32: (debug, variadic out) + * Read 32bit words from the indirect memory map + */ +#define MC_CMD_CSR_READ32 0x0c +#define MC_CMD_CSR_READ32_IN_LEN 12 +#define MC_CMD_CSR_READ32_IN_ADDR_OFST 0 +#define MC_CMD_CSR_READ32_IN_STEP_OFST 4 +#define MC_CMD_CSR_READ32_IN_NUMWORDS_OFST 8 +#define MC_CMD_CSR_READ32_OUT_LEN(_numwords) \ + (((_numwords) * 4) + 4) +/* IN.NUMWORDS of 32bit words start here */ +#define MC_CMD_CSR_READ32_OUT_BUFFER_OFST 0 +#define MC_CMD_CSR_READ32_OUT_IREG_STATUS_OFST(_numwords) \ + ((_numwords) * 4) + +/* MC_CMD_CSR_WRITE32: (debug, variadic in) + * Write 32bit dwords to the indirect memory map + */ +#define MC_CMD_CSR_WRITE32 0x0d +#define MC_CMD_CSR_WRITE32_IN_LEN(_numwords) \ + (((_numwords) * 4) + 8) +#define MC_CMD_CSR_WRITE32_IN_ADDR_OFST 0 +#define MC_CMD_CSR_WRITE32_IN_STEP_OFST 4 +/* Multiple 32bit words of data to write start here */ +#define MC_CMD_CSR_WRITE32_IN_BUFFER_OFST 8 +#define MC_CMD_CSR_WRITE32_OUT_LEN 4 +#define MC_CMD_CSR_WRITE32_OUT_STATUS_OFST 0 + +/* MC_CMD_JTAG_WORK: (debug, fpga only) + * Process JTAG work buffer for RBF acceleration. + * + * Host: bit count, (up to) 32 words of data to clock out to JTAG + * (bits 1,0=TMS,TDO for first bit; bits 3,2=TMS,TDO for second bit, etc.) + * MC: bit count, (up to) 32 words of data clocked in from JTAG + * (bit 0=TDI for first bit, bit 1=TDI for second bit, etc.; [31:16] unused) + */ +#define MC_CMD_JTAG_WORK 0x0e + +/* MC_CMD_STACKINFO: (debug, variadic out) + * Get stack information + * + * Host: nothing + * MC: (thread ptr, stack size, free space) for each thread in system + */ +#define MC_CMD_STACKINFO 0x0f + +/* MC_CMD_MDIO_READ: + * MDIO register read + */ +#define MC_CMD_MDIO_READ 0x10 +#define MC_CMD_MDIO_READ_IN_LEN 16 +#define MC_CMD_MDIO_READ_IN_BUS_OFST 0 +#define MC_CMD_MDIO_READ_IN_PRTAD_OFST 4 +#define MC_CMD_MDIO_READ_IN_DEVAD_OFST 8 +#define MC_CMD_MDIO_READ_IN_ADDR_OFST 12 +#define MC_CMD_MDIO_READ_OUT_LEN 8 +#define MC_CMD_MDIO_READ_OUT_VALUE_OFST 0 +#define MC_CMD_MDIO_READ_OUT_STATUS_OFST 4 + +/* MC_CMD_MDIO_WRITE: + * MDIO register write + */ +#define MC_CMD_MDIO_WRITE 0x11 +#define MC_CMD_MDIO_WRITE_IN_LEN 20 +#define MC_CMD_MDIO_WRITE_IN_BUS_OFST 0 +#define MC_CMD_MDIO_WRITE_IN_PRTAD_OFST 4 +#define MC_CMD_MDIO_WRITE_IN_DEVAD_OFST 8 +#define MC_CMD_MDIO_WRITE_IN_ADDR_OFST 12 +#define MC_CMD_MDIO_WRITE_IN_VALUE_OFST 16 +#define MC_CMD_MDIO_WRITE_OUT_LEN 4 +#define MC_CMD_MDIO_WRITE_OUT_STATUS_OFST 0 + +/* By default all the MCDI MDIO operations perform clause45 mode. + * If you want to use clause22 then set DEVAD = MC_CMD_MDIO_CLAUSE22. + */ +#define MC_CMD_MDIO_CLAUSE22 32 + +/* There are two MDIO buses: one for the internal PHY, and one for external + * devices. + */ +#define MC_CMD_MDIO_BUS_INTERNAL 0 +#define MC_CMD_MDIO_BUS_EXTERNAL 1 + +/* The MDIO commands return the raw status bits from the MDIO block. A "good" + * transaction should have the DONE bit set and all other bits clear. + */ +#define MC_CMD_MDIO_STATUS_GOOD 0x08 + + +/* MC_CMD_DBI_WRITE: (debug) + * Write DBI register(s) + * + * Host: address, byte-enables (and VF selection, and cs2 flag), + * value [,address ...] + * MC: nothing + */ +#define MC_CMD_DBI_WRITE 0x12 +#define MC_CMD_DBI_WRITE_IN_LEN(_numwords) \ + (12 * (_numwords)) +#define MC_CMD_DBI_WRITE_IN_ADDRESS_OFST(_word) \ + (((_word) * 12) + 0) +#define MC_CMD_DBI_WRITE_IN_BYTE_MASK_OFST(_word) \ + (((_word) * 12) + 4) +#define MC_CMD_DBI_WRITE_IN_VALUE_OFST(_word) \ + (((_word) * 12) + 8) +#define MC_CMD_DBI_WRITE_OUT_LEN 0 + +/* MC_CMD_DBI_READ: (debug) + * Read DBI register(s) + * + * Host: address, [,address ...] + * MC: value [,value ...] + * (note: this does not support reading from VFs, but is retained for backwards + * compatibility; see MC_CMD_DBI_READX below) + */ +#define MC_CMD_DBI_READ 0x13 +#define MC_CMD_DBI_READ_IN_LEN(_numwords) \ + (4 * (_numwords)) +#define MC_CMD_DBI_READ_OUT_LEN(_numwords) \ + (4 * (_numwords)) + +/* MC_CMD_PORT_READ32: (debug) + * Read a 32-bit register from the indirect port register map. + * + * The port to access is implied by the Shared memory channel used. + */ +#define MC_CMD_PORT_READ32 0x14 +#define MC_CMD_PORT_READ32_IN_LEN 4 +#define MC_CMD_PORT_READ32_IN_ADDR_OFST 0 +#define MC_CMD_PORT_READ32_OUT_LEN 8 +#define MC_CMD_PORT_READ32_OUT_VALUE_OFST 0 +#define MC_CMD_PORT_READ32_OUT_STATUS_OFST 4 + +/* MC_CMD_PORT_WRITE32: (debug) + * Write a 32-bit register to the indirect port register map. + * + * The port to access is implied by the Shared memory channel used. + */ +#define MC_CMD_PORT_WRITE32 0x15 +#define MC_CMD_PORT_WRITE32_IN_LEN 8 +#define MC_CMD_PORT_WRITE32_IN_ADDR_OFST 0 +#define MC_CMD_PORT_WRITE32_IN_VALUE_OFST 4 +#define MC_CMD_PORT_WRITE32_OUT_LEN 4 +#define MC_CMD_PORT_WRITE32_OUT_STATUS_OFST 0 + +/* MC_CMD_PORT_READ128: (debug) + * Read a 128-bit register from indirect port register map + * + * The port to access is implied by the Shared memory channel used. + */ +#define MC_CMD_PORT_READ128 0x16 +#define MC_CMD_PORT_READ128_IN_LEN 4 +#define MC_CMD_PORT_READ128_IN_ADDR_OFST 0 +#define MC_CMD_PORT_READ128_OUT_LEN 20 +#define MC_CMD_PORT_READ128_OUT_VALUE_OFST 0 +#define MC_CMD_PORT_READ128_OUT_STATUS_OFST 16 + +/* MC_CMD_PORT_WRITE128: (debug) + * Write a 128-bit register to indirect port register map. + * + * The port to access is implied by the Shared memory channel used. + */ +#define MC_CMD_PORT_WRITE128 0x17 +#define MC_CMD_PORT_WRITE128_IN_LEN 20 +#define MC_CMD_PORT_WRITE128_IN_ADDR_OFST 0 +#define MC_CMD_PORT_WRITE128_IN_VALUE_OFST 4 +#define MC_CMD_PORT_WRITE128_OUT_LEN 4 +#define MC_CMD_PORT_WRITE128_OUT_STATUS_OFST 0 + +/* MC_CMD_GET_BOARD_CFG: + * Returns the MC firmware configuration structure + * + * The FW_SUBTYPE_LIST contains a 16-bit value for each of the 12 types of + * NVRAM area. The values are defined in the firmware/mc/platform/<xxx>.c file + * for a specific board type, but otherwise have no meaning to the MC; they + * are used by the driver to manage selection of appropriate firmware updates. + */ +#define MC_CMD_GET_BOARD_CFG 0x18 +#define MC_CMD_GET_BOARD_CFG_IN_LEN 0 +#define MC_CMD_GET_BOARD_CFG_OUT_LEN 96 +#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_TYPE_OFST 0 +#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_NAME_OFST 4 +#define MC_CMD_GET_BOARD_CFG_OUT_BOARD_NAME_LEN 32 +#define MC_CMD_GET_BOARD_CFG_OUT_CAPABILITIES_PORT0_OFST 36 +#define MC_CMD_GET_BOARD_CFG_OUT_CAPABILITIES_PORT1_OFST 40 +#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST 44 +#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_LEN 6 +#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST 50 +#define MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_LEN 6 +#define MC_CMD_GET_BOARD_CFG_OUT_MAC_COUNT_PORT0_OFST 56 +#define MC_CMD_GET_BOARD_CFG_OUT_MAC_COUNT_PORT1_OFST 60 +#define MC_CMD_GET_BOARD_CFG_OUT_MAC_STRIDE_PORT0_OFST 64 +#define MC_CMD_GET_BOARD_CFG_OUT_MAC_STRIDE_PORT1_OFST 68 +#define MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_OFST 72 +#define MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN 24 + +/* MC_CMD_DBI_READX: (debug) + * Read DBI register(s) -- extended functionality + * + * Host: vf selection, address, [,vf selection ...] + * MC: value [,value ...] + */ +#define MC_CMD_DBI_READX 0x19 +#define MC_CMD_DBI_READX_IN_LEN(_numwords) \ + (8*(_numwords)) +#define MC_CMD_DBI_READX_OUT_LEN(_numwords) \ + (4*(_numwords)) + +/* MC_CMD_SET_RAND_SEED: + * Set the 16byte seed for the MC psuedo-random generator + */ +#define MC_CMD_SET_RAND_SEED 0x1a +#define MC_CMD_SET_RAND_SEED_IN_LEN 16 +#define MC_CMD_SET_RAND_SEED_IN_SEED_OFST 0 +#define MC_CMD_SET_RAND_SEED_OUT_LEN 0 + +/* MC_CMD_LTSSM_HIST: (debug) + * Retrieve the history of the LTSSM, if the build supports it. + * + * Host: nothing + * MC: variable number of LTSSM values, as bytes + * The history is read-to-clear. + */ +#define MC_CMD_LTSSM_HIST 0x1b + +/* MC_CMD_DRV_ATTACH: + * Inform MCPU that this port is managed on the host (i.e. driver active) + */ +#define MC_CMD_DRV_ATTACH 0x1c +#define MC_CMD_DRV_ATTACH_IN_LEN 8 +#define MC_CMD_DRV_ATTACH_IN_NEW_STATE_OFST 0 +#define MC_CMD_DRV_ATTACH_IN_UPDATE_OFST 4 +#define MC_CMD_DRV_ATTACH_OUT_LEN 4 +#define MC_CMD_DRV_ATTACH_OUT_OLD_STATE_OFST 0 + +/* MC_CMD_NCSI_PROD: (debug) + * Trigger an NC-SI event (and possibly an AEN in response) + */ +#define MC_CMD_NCSI_PROD 0x1d +#define MC_CMD_NCSI_PROD_IN_LEN 4 +#define MC_CMD_NCSI_PROD_IN_EVENTS_OFST 0 +#define MC_CMD_NCSI_PROD_LINKCHANGE_LBN 0 +#define MC_CMD_NCSI_PROD_LINKCHANGE_WIDTH 1 +#define MC_CMD_NCSI_PROD_RESET_LBN 1 +#define MC_CMD_NCSI_PROD_RESET_WIDTH 1 +#define MC_CMD_NCSI_PROD_DRVATTACH_LBN 2 +#define MC_CMD_NCSI_PROD_DRVATTACH_WIDTH 1 +#define MC_CMD_NCSI_PROD_OUT_LEN 0 + +/* Enumeration */ +#define MC_CMD_NCSI_PROD_LINKCHANGE 0 +#define MC_CMD_NCSI_PROD_RESET 1 +#define MC_CMD_NCSI_PROD_DRVATTACH 2 + +/* MC_CMD_DEVEL: (debug) + * Reserved for development + */ +#define MC_CMD_DEVEL 0x1e + +/* MC_CMD_SHMUART: (debug) + * Route UART output to circular buffer in shared memory instead. + */ +#define MC_CMD_SHMUART 0x1f +#define MC_CMD_SHMUART_IN_FLAG_OFST 0 +#define MC_CMD_SHMUART_IN_LEN 4 +#define MC_CMD_SHMUART_OUT_LEN 0 + +/* MC_CMD_PORT_RESET: + * Generic per-port reset. There is no equivalent for per-board reset. + * + * Locks required: None + * Return code: 0, ETIME + */ +#define MC_CMD_PORT_RESET 0x20 +#define MC_CMD_PORT_RESET_IN_LEN 0 +#define MC_CMD_PORT_RESET_OUT_LEN 0 + +/* MC_CMD_RESOURCE_LOCK: + * Generic resource lock/unlock interface. + * + * Locks required: None + * Return code: 0, + * EBUSY (if trylock is contended by other port), + * EDEADLK (if trylock is already acquired by this port) + * EINVAL (if unlock doesn't own the lock) + */ +#define MC_CMD_RESOURCE_LOCK 0x21 +#define MC_CMD_RESOURCE_LOCK_IN_LEN 8 +#define MC_CMD_RESOURCE_LOCK_IN_ACTION_OFST 0 +#define MC_CMD_RESOURCE_LOCK_ACTION_TRYLOCK 1 +#define MC_CMD_RESOURCE_LOCK_ACTION_UNLOCK 0 +#define MC_CMD_RESOURCE_LOCK_IN_RESOURCE_OFST 4 +#define MC_CMD_RESOURCE_LOCK_I2C 2 +#define MC_CMD_RESOURCE_LOCK_PHY 3 +#define MC_CMD_RESOURCE_LOCK_OUT_LEN 0 + +/* MC_CMD_SPI_COMMAND: (variadic in, variadic out) + * Read/Write to/from the SPI device. + * + * Locks required: SPI_LOCK + * Return code: 0, ETIME, EINVAL, EACCES (if SPI_LOCK is not held) + */ +#define MC_CMD_SPI_COMMAND 0x22 +#define MC_CMD_SPI_COMMAND_IN_LEN(_write_bytes) (12 + (_write_bytes)) +#define MC_CMD_SPI_COMMAND_IN_ARGS_OFST 0 +#define MC_CMD_SPI_COMMAND_IN_ARGS_ADDRESS_OFST 0 +#define MC_CMD_SPI_COMMAND_IN_ARGS_READ_BYTES_OFST 4 +#define MC_CMD_SPI_COMMAND_IN_ARGS_CHIP_SELECT_OFST 8 +/* Data to write here */ +#define MC_CMD_SPI_COMMAND_IN_WRITE_BUFFER_OFST 12 +#define MC_CMD_SPI_COMMAND_OUT_LEN(_read_bytes) (_read_bytes) +/* Data read here */ +#define MC_CMD_SPI_COMMAND_OUT_READ_BUFFER_OFST 0 + +/* MC_CMD_I2C_READ_WRITE: (variadic in, variadic out) + * Read/Write to/from the I2C bus. + * + * Locks required: I2C_LOCK + * Return code: 0, ETIME, EINVAL, EACCES (if I2C_LOCK is not held) + */ +#define MC_CMD_I2C_RW 0x23 +#define MC_CMD_I2C_RW_IN_LEN(_write_bytes) (8 + (_write_bytes)) +#define MC_CMD_I2C_RW_IN_ARGS_OFST 0 +#define MC_CMD_I2C_RW_IN_ARGS_ADDR_OFST 0 +#define MC_CMD_I2C_RW_IN_ARGS_READ_BYTES_OFST 4 +/* Data to write here */ +#define MC_CMD_I2C_RW_IN_WRITE_BUFFER_OFSET 8 +#define MC_CMD_I2C_RW_OUT_LEN(_read_bytes) (_read_bytes) +/* Data read here */ +#define MC_CMD_I2C_RW_OUT_READ_BUFFER_OFST 0 + +/* Generic phy capability bitmask */ +#define MC_CMD_PHY_CAP_10HDX_LBN 1 +#define MC_CMD_PHY_CAP_10HDX_WIDTH 1 +#define MC_CMD_PHY_CAP_10FDX_LBN 2 +#define MC_CMD_PHY_CAP_10FDX_WIDTH 1 +#define MC_CMD_PHY_CAP_100HDX_LBN 3 +#define MC_CMD_PHY_CAP_100HDX_WIDTH 1 +#define MC_CMD_PHY_CAP_100FDX_LBN 4 +#define MC_CMD_PHY_CAP_100FDX_WIDTH 1 +#define MC_CMD_PHY_CAP_1000HDX_LBN 5 +#define MC_CMD_PHY_CAP_1000HDX_WIDTH 1 +#define MC_CMD_PHY_CAP_1000FDX_LBN 6 +#define MC_CMD_PHY_CAP_1000FDX_WIDTH 1 +#define MC_CMD_PHY_CAP_10000FDX_LBN 7 +#define MC_CMD_PHY_CAP_10000FDX_WIDTH 1 +#define MC_CMD_PHY_CAP_PAUSE_LBN 8 +#define MC_CMD_PHY_CAP_PAUSE_WIDTH 1 +#define MC_CMD_PHY_CAP_ASYM_LBN 9 +#define MC_CMD_PHY_CAP_ASYM_WIDTH 1 +#define MC_CMD_PHY_CAP_AN_LBN 10 +#define MC_CMD_PHY_CAP_AN_WIDTH 1 + +/* Generic loopback enumeration */ +#define MC_CMD_LOOPBACK_NONE 0 +#define MC_CMD_LOOPBACK_DATA 1 +#define MC_CMD_LOOPBACK_GMAC 2 +#define MC_CMD_LOOPBACK_XGMII 3 +#define MC_CMD_LOOPBACK_XGXS 4 +#define MC_CMD_LOOPBACK_XAUI 5 +#define MC_CMD_LOOPBACK_GMII 6 +#define MC_CMD_LOOPBACK_SGMII 7 +#define MC_CMD_LOOPBACK_XGBR 8 +#define MC_CMD_LOOPBACK_XFI 9 +#define MC_CMD_LOOPBACK_XAUI_FAR 10 +#define MC_CMD_LOOPBACK_GMII_FAR 11 +#define MC_CMD_LOOPBACK_SGMII_FAR 12 +#define MC_CMD_LOOPBACK_XFI_FAR 13 +#define MC_CMD_LOOPBACK_GPHY 14 +#define MC_CMD_LOOPBACK_PHYXS 15 +#define MC_CMD_LOOPBACK_PCS 16 +#define MC_CMD_LOOPBACK_PMAPMD 17 +#define MC_CMD_LOOPBACK_XPORT 18 +#define MC_CMD_LOOPBACK_XGMII_WS 19 +#define MC_CMD_LOOPBACK_XAUI_WS 20 +#define MC_CMD_LOOPBACK_XAUI_WS_FAR 21 +#define MC_CMD_LOOPBACK_XAUI_WS_NEAR 22 +#define MC_CMD_LOOPBACK_GMII_WS 23 +#define MC_CMD_LOOPBACK_XFI_WS 24 +#define MC_CMD_LOOPBACK_XFI_WS_FAR 25 +#define MC_CMD_LOOPBACK_PHYXS_WS 26 + +/* Generic PHY statistics enumeration */ +#define MC_CMD_OUI 0 +#define MC_CMD_PMA_PMD_LINK_UP 1 +#define MC_CMD_PMA_PMD_RX_FAULT 2 +#define MC_CMD_PMA_PMD_TX_FAULT 3 +#define MC_CMD_PMA_PMD_SIGNAL 4 +#define MC_CMD_PMA_PMD_SNR_A 5 +#define MC_CMD_PMA_PMD_SNR_B 6 +#define MC_CMD_PMA_PMD_SNR_C 7 +#define MC_CMD_PMA_PMD_SNR_D 8 +#define MC_CMD_PCS_LINK_UP 9 +#define MC_CMD_PCS_RX_FAULT 10 +#define MC_CMD_PCS_TX_FAULT 11 +#define MC_CMD_PCS_BER 12 +#define MC_CMD_PCS_BLOCK_ERRORS 13 +#define MC_CMD_PHYXS_LINK_UP 14 +#define MC_CMD_PHYXS_RX_FAULT 15 +#define MC_CMD_PHYXS_TX_FAULT 16 +#define MC_CMD_PHYXS_ALIGN 17 +#define MC_CMD_PHYXS_SYNC 18 +#define MC_CMD_AN_LINK_UP 19 +#define MC_CMD_AN_COMPLETE 20 +#define MC_CMD_AN_10GBT_STATUS 21 +#define MC_CMD_CL22_LINK_UP 22 +#define MC_CMD_PHY_NSTATS 23 + +/* MC_CMD_GET_PHY_CFG: + * Report PHY configuration. This guarantees to succeed even if the PHY is in + * a "zombie" state. + * + * Locks required: None + * Return code: 0 + */ +#define MC_CMD_GET_PHY_CFG 0x24 + +#define MC_CMD_GET_PHY_CFG_IN_LEN 0 +#define MC_CMD_GET_PHY_CFG_OUT_LEN 72 + +#define MC_CMD_GET_PHY_CFG_OUT_FLAGS_OFST 0 +#define MC_CMD_GET_PHY_CFG_PRESENT_LBN 0 +#define MC_CMD_GET_PHY_CFG_PRESENT_WIDTH 1 +#define MC_CMD_GET_PHY_CFG_SHORTBIST_LBN 1 +#define MC_CMD_GET_PHY_CFG_SHORTBIST_WIDTH 1 +#define MC_CMD_GET_PHY_CFG_LONGBIST_LBN 2 +#define MC_CMD_GET_PHY_CFG_LONGBIST_WIDTH 1 +#define MC_CMD_GET_PHY_CFG_LOWPOWER_LBN 3 +#define MC_CMD_GET_PHY_CFG_LOWPOWER_WIDTH 1 +#define MC_CMD_GET_PHY_CFG_POWEROFF_LBN 4 +#define MC_CMD_GET_PHY_CFG_POWEROFF_WIDTH 1 +#define MC_CMD_GET_PHY_CFG_TXDIS_LBN 5 +#define MC_CMD_GET_PHY_CFG_TXDIS_WIDTH 1 +#define MC_CMD_GET_PHY_CFG_OUT_TYPE_OFST 4 +/* Bitmask of supported capabilities */ +#define MC_CMD_GET_PHY_CFG_OUT_SUPPORTED_CAP_OFST 8 +#define MC_CMD_GET_PHY_CFG_OUT_CHANNEL_OFST 12 +#define MC_CMD_GET_PHY_CFG_OUT_PRT_OFST 16 +/* PHY statistics bitmap */ +#define MC_CMD_GET_PHY_CFG_OUT_STATS_MASK_OFST 20 +/* PHY type/name string */ +#define MC_CMD_GET_PHY_CFG_OUT_NAME_OFST 24 +#define MC_CMD_GET_PHY_CFG_OUT_NAME_LEN 20 +#define MC_CMD_GET_PHY_CFG_OUT_MEDIA_TYPE_OFST 44 +#define MC_CMD_MEDIA_XAUI 1 +#define MC_CMD_MEDIA_CX4 2 +#define MC_CMD_MEDIA_KX4 3 +#define MC_CMD_MEDIA_XFP 4 +#define MC_CMD_MEDIA_SFP_PLUS 5 +#define MC_CMD_MEDIA_BASE_T 6 +/* MDIO "MMDS" supported */ +#define MC_CMD_GET_PHY_CFG_OUT_MMD_MASK_OFST 48 +/* Native clause 22 */ +#define MC_CMD_MMD_CLAUSE22 0 +#define MC_CMD_MMD_CLAUSE45_PMAPMD 1 +#define MC_CMD_MMD_CLAUSE45_WIS 2 +#define MC_CMD_MMD_CLAUSE45_PCS 3 +#define MC_CMD_MMD_CLAUSE45_PHYXS 4 +#define MC_CMD_MMD_CLAUSE45_DTEXS 5 +#define MC_CMD_MMD_CLAUSE45_TC 6 +#define MC_CMD_MMD_CLAUSE45_AN 7 +/* Clause22 proxied over clause45 by PHY */ +#define MC_CMD_MMD_CLAUSE45_C22EXT 29 +#define MC_CMD_MMD_CLAUSE45_VEND1 30 +#define MC_CMD_MMD_CLAUSE45_VEND2 31 +/* PHY stepping version */ +#define MC_CMD_GET_PHY_CFG_OUT_REVISION_OFST 52 +#define MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN 20 + +/* MC_CMD_START_PHY_BIST: + * Start a BIST test on the PHY. + * + * Locks required: PHY_LOCK if doing a PHY BIST + * Return code: 0, EINVAL, EACCES (if PHY_LOCK is not held) + */ +#define MC_CMD_START_BIST 0x25 +#define MC_CMD_START_BIST_IN_LEN 4 +#define MC_CMD_START_BIST_TYPE_OFST 0 + +/* Run the PHY's short BIST */ +#define MC_CMD_PHY_BIST_SHORT 1 +/* Run the PHY's long BIST */ +#define MC_CMD_PHY_BIST_LONG 2 +/* Run BIST on the currently selected BPX Serdes (XAUI or XFI) */ +#define MC_CMD_BPX_SERDES_BIST 3 + +/* MC_CMD_POLL_PHY_BIST: (variadic output) + * Poll for BIST completion + * + * Returns a single status code, and a binary blob of phy-specific + * bist output. If the driver can't succesfully parse the BIST output, + * it should still respect the Pass/Fail in OUT.RESULT. + * + * Locks required: PHY_LOCK if doing a PHY BIST + * Return code: 0, EACCES (if PHY_LOCK is not held) + */ +#define MC_CMD_POLL_BIST 0x26 +#define MC_CMD_POLL_BIST_IN_LEN 0 +#define MC_CMD_POLL_BIST_OUT_LEN UNKNOWN +#define MC_CMD_POLL_BIST_OUT_RESULT_OFST 0 +#define MC_CMD_POLL_BIST_RUNNING 1 +#define MC_CMD_POLL_BIST_PASSED 2 +#define MC_CMD_POLL_BIST_FAILED 3 +#define MC_CMD_POLL_BIST_TIMEOUT 4 +#define MC_CMD_POLL_BIST_OUT_PRIVATE_OFST 4 + +/* MC_CMD_PHY_SPI: (variadic in, variadic out) + * Read/Write/Erase the PHY SPI device + * + * Locks required: PHY_LOCK + * Return code: 0, ETIME, EINVAL, EACCES (if PHY_LOCK is not held) + */ +#define MC_CMD_PHY_SPI 0x27 +#define MC_CMD_PHY_SPI_IN_LEN(_write_bytes) (12 + (_write_bytes)) +#define MC_CMD_PHY_SPI_IN_ARGS_OFST 0 +#define MC_CMD_PHY_SPI_IN_ARGS_ADDR_OFST 0 +#define MC_CMD_PHY_SPI_IN_ARGS_READ_BYTES_OFST 4 +#define MC_CMD_PHY_SPI_IN_ARGS_ERASE_ALL_OFST 8 +/* Data to write here */ +#define MC_CMD_PHY_SPI_IN_WRITE_BUFFER_OFSET 12 +#define MC_CMD_PHY_SPI_OUT_LEN(_read_bytes) (_read_bytes) +/* Data read here */ +#define MC_CMD_PHY_SPI_OUT_READ_BUFFER_OFST 0 + + +/* MC_CMD_GET_LOOPBACK_MODES: + * Returns a bitmask of loopback modes evailable at each speed. + * + * Locks required: None + * Return code: 0 + */ +#define MC_CMD_GET_LOOPBACK_MODES 0x28 +#define MC_CMD_GET_LOOPBACK_MODES_IN_LEN 0 +#define MC_CMD_GET_LOOPBACK_MODES_OUT_LEN 32 +#define MC_CMD_GET_LOOPBACK_MODES_100M_OFST 0 +#define MC_CMD_GET_LOOPBACK_MODES_1G_OFST 8 +#define MC_CMD_GET_LOOPBACK_MODES_10G_OFST 16 +#define MC_CMD_GET_LOOPBACK_MODES_SUGGESTED_OFST 24 + +/* Flow control enumeration */ +#define MC_CMD_FCNTL_OFF 0 +#define MC_CMD_FCNTL_RESPOND 1 +#define MC_CMD_FCNTL_BIDIR 2 +/* Auto - Use what the link has autonegotiated + * - The driver should modify the advertised capabilities via SET_LINK.CAP + * to control the negotiated flow control mode. + * - Can only be set if the PHY supports PAUSE+ASYM capabilities + * - Never returned by GET_LINK as the value programmed into the MAC + */ +#define MC_CMD_FCNTL_AUTO 3 + +/* Generic mac fault bitmask */ +#define MC_CMD_MAC_FAULT_XGMII_LOCAL_LBN 0 +#define MC_CMD_MAC_FAULT_XGMII_LOCAL_WIDTH 1 +#define MC_CMD_MAC_FAULT_XGMII_REMOTE_LBN 1 +#define MC_CMD_MAC_FAULT_XGMII_REMOTE_WIDTH 1 +#define MC_CMD_MAC_FAULT_SGMII_REMOTE_LBN 2 +#define MC_CMD_MAC_FAULT_SGMII_REMOTE_WIDTH 1 + +/* MC_CMD_GET_LINK: + * Read the unified MAC/PHY link state + * + * Locks required: None + * Return code: 0, ETIME + */ +#define MC_CMD_GET_LINK 0x29 +#define MC_CMD_GET_LINK_IN_LEN 0 +#define MC_CMD_GET_LINK_OUT_LEN 28 +/* near-side and link-partner advertised capabilities */ +#define MC_CMD_GET_LINK_OUT_CAP_OFST 0 +#define MC_CMD_GET_LINK_OUT_LP_CAP_OFST 4 +/* Autonegotiated speed in mbit/s. The link may still be down + * even if this reads non-zero */ +#define MC_CMD_GET_LINK_OUT_LINK_SPEED_OFST 8 +#define MC_CMD_GET_LINK_OUT_LOOPBACK_MODE_OFST 12 +#define MC_CMD_GET_LINK_OUT_FLAGS_OFST 16 +/* Whether we have overall link up */ +#define MC_CMD_GET_LINK_LINK_UP_LBN 0 +#define MC_CMD_GET_LINK_LINK_UP_WIDTH 1 +#define MC_CMD_GET_LINK_FULL_DUPLEX_LBN 1 +#define MC_CMD_GET_LINK_FULL_DUPLEX_WIDTH 1 +/* Whether we have link at the layers provided by the BPX */ +#define MC_CMD_GET_LINK_BPX_LINK_LBN 2 +#define MC_CMD_GET_LINK_BPX_LINK_WIDTH 1 +/* Whether the PHY has external link */ +#define MC_CMD_GET_LINK_PHY_LINK_LBN 3 +#define MC_CMD_GET_LINK_PHY_LINK_WIDTH 1 +#define MC_CMD_GET_LINK_OUT_FCNTL_OFST 20 +#define MC_CMD_GET_LINK_OUT_MAC_FAULT_OFST 24 + +/* MC_CMD_SET_LINK: + * Write the unified MAC/PHY link configuration + * + * A loopback speed of "0" is supported, and means + * (choose any available speed) + * + * Locks required: None + * Return code: 0, EINVAL, ETIME + */ +#define MC_CMD_SET_LINK 0x2a +#define MC_CMD_SET_LINK_IN_LEN 16 +#define MC_CMD_SET_LINK_IN_CAP_OFST 0 +#define MC_CMD_SET_LINK_IN_FLAGS_OFST 4 +#define MC_CMD_SET_LINK_LOWPOWER_LBN 0 +#define MC_CMD_SET_LINK_LOWPOWER_WIDTH 1 +#define MC_CMD_SET_LINK_POWEROFF_LBN 1 +#define MC_CMD_SET_LINK_POWEROFF_WIDTH 1 +#define MC_CMD_SET_LINK_TXDIS_LBN 2 +#define MC_CMD_SET_LINK_TXDIS_WIDTH 1 +#define MC_CMD_SET_LINK_IN_LOOPBACK_MODE_OFST 8 +#define MC_CMD_SET_LINK_IN_LOOPBACK_SPEED_OFST 12 +#define MC_CMD_SET_LINK_OUT_LEN 0 + +/* MC_CMD_SET_ID_LED: + * Set indentification LED state + * + * Locks required: None + * Return code: 0, EINVAL + */ +#define MC_CMD_SET_ID_LED 0x2b +#define MC_CMD_SET_ID_LED_IN_LEN 4 +#define MC_CMD_SET_ID_LED_IN_STATE_OFST 0 +#define MC_CMD_LED_OFF 0 +#define MC_CMD_LED_ON 1 +#define MC_CMD_LED_DEFAULT 2 +#define MC_CMD_SET_ID_LED_OUT_LEN 0 + +/* MC_CMD_SET_MAC: + * Set MAC configuration + * + * The MTU is the MTU programmed directly into the XMAC/GMAC + * (inclusive of EtherII, VLAN, bug16011 padding) + * + * Locks required: None + * Return code: 0, EINVAL + */ +#define MC_CMD_SET_MAC 0x2c +#define MC_CMD_SET_MAC_IN_LEN 24 +#define MC_CMD_SET_MAC_IN_MTU_OFST 0 +#define MC_CMD_SET_MAC_IN_DRAIN_OFST 4 +#define MC_CMD_SET_MAC_IN_ADDR_OFST 8 +#define MC_CMD_SET_MAC_IN_REJECT_OFST 16 +#define MC_CMD_SET_MAC_IN_REJECT_UNCST_LBN 0 +#define MC_CMD_SET_MAC_IN_REJECT_UNCST_WIDTH 1 +#define MC_CMD_SET_MAC_IN_REJECT_BRDCST_LBN 1 +#define MC_CMD_SET_MAC_IN_REJECT_BRDCST_WIDTH 1 +#define MC_CMD_SET_MAC_IN_FCNTL_OFST 20 +#define MC_CMD_SET_MAC_OUT_LEN 0 + +/* MC_CMD_PHY_STATS: + * Get generic PHY statistics + * + * This call returns the statistics for a generic PHY, by direct DMA + * into host memory, in a sparse array (indexed by the enumerate). + * Each value is represented by a 32bit number. + * + * Locks required: None + * Returns: 0, ETIME + * Response methods: shared memory, event + */ +#define MC_CMD_PHY_STATS 0x2d +#define MC_CMD_PHY_STATS_IN_LEN 8 +#define MC_CMD_PHY_STATS_IN_DMA_ADDR_LO_OFST 0 +#define MC_CMD_PHY_STATS_IN_DMA_ADDR_HI_OFST 4 +#define MC_CMD_PHY_STATS_OUT_LEN 0 + +/* Unified MAC statistics enumeration */ +#define MC_CMD_MAC_GENERATION_START 0 +#define MC_CMD_MAC_TX_PKTS 1 +#define MC_CMD_MAC_TX_PAUSE_PKTS 2 +#define MC_CMD_MAC_TX_CONTROL_PKTS 3 +#define MC_CMD_MAC_TX_UNICAST_PKTS 4 +#define MC_CMD_MAC_TX_MULTICAST_PKTS 5 +#define MC_CMD_MAC_TX_BROADCAST_PKTS 6 +#define MC_CMD_MAC_TX_BYTES 7 +#define MC_CMD_MAC_TX_BAD_BYTES 8 +#define MC_CMD_MAC_TX_LT64_PKTS 9 +#define MC_CMD_MAC_TX_64_PKTS 10 +#define MC_CMD_MAC_TX_65_TO_127_PKTS 11 +#define MC_CMD_MAC_TX_128_TO_255_PKTS 12 +#define MC_CMD_MAC_TX_256_TO_511_PKTS 13 +#define MC_CMD_MAC_TX_512_TO_1023_PKTS 14 +#define MC_CMD_MAC_TX_1024_TO_15XX_PKTS 15 +#define MC_CMD_MAC_TX_15XX_TO_JUMBO_PKTS 16 +#define MC_CMD_MAC_TX_GTJUMBO_PKTS 17 +#define MC_CMD_MAC_TX_BAD_FCS_PKTS 18 +#define MC_CMD_MAC_TX_SINGLE_COLLISION_PKTS 19 +#define MC_CMD_MAC_TX_MULTIPLE_COLLISION_PKTS 20 +#define MC_CMD_MAC_TX_EXCESSIVE_COLLISION_PKTS 21 +#define MC_CMD_MAC_TX_LATE_COLLISION_PKTS 22 +#define MC_CMD_MAC_TX_DEFERRED_PKTS 23 +#define MC_CMD_MAC_TX_EXCESSIVE_DEFERRED_PKTS 24 +#define MC_CMD_MAC_TX_NON_TCPUDP_PKTS 25 +#define MC_CMD_MAC_TX_MAC_SRC_ERR_PKTS 26 +#define MC_CMD_MAC_TX_IP_SRC_ERR_PKTS 27 +#define MC_CMD_MAC_RX_PKTS 28 +#define MC_CMD_MAC_RX_PAUSE_PKTS 29 +#define MC_CMD_MAC_RX_GOOD_PKTS 30 +#define MC_CMD_MAC_RX_CONTROL_PKTS 31 +#define MC_CMD_MAC_RX_UNICAST_PKTS 32 +#define MC_CMD_MAC_RX_MULTICAST_PKTS 33 +#define MC_CMD_MAC_RX_BROADCAST_PKTS 34 +#define MC_CMD_MAC_RX_BYTES 35 +#define MC_CMD_MAC_RX_BAD_BYTES 36 +#define MC_CMD_MAC_RX_64_PKTS 37 +#define MC_CMD_MAC_RX_65_TO_127_PKTS 38 +#define MC_CMD_MAC_RX_128_TO_255_PKTS 39 +#define MC_CMD_MAC_RX_256_TO_511_PKTS 40 +#define MC_CMD_MAC_RX_512_TO_1023_PKTS 41 +#define MC_CMD_MAC_RX_1024_TO_15XX_PKTS 42 +#define MC_CMD_MAC_RX_15XX_TO_JUMBO_PKTS 43 +#define MC_CMD_MAC_RX_GTJUMBO_PKTS 44 +#define MC_CMD_MAC_RX_UNDERSIZE_PKTS 45 +#define MC_CMD_MAC_RX_BAD_FCS_PKTS 46 +#define MC_CMD_MAC_RX_OVERFLOW_PKTS 47 +#define MC_CMD_MAC_RX_FALSE_CARRIER_PKTS 48 +#define MC_CMD_MAC_RX_SYMBOL_ERROR_PKTS 49 +#define MC_CMD_MAC_RX_ALIGN_ERROR_PKTS 50 +#define MC_CMD_MAC_RX_LENGTH_ERROR_PKTS 51 +#define MC_CMD_MAC_RX_INTERNAL_ERROR_PKTS 52 +#define MC_CMD_MAC_RX_JABBER_PKTS 53 +#define MC_CMD_MAC_RX_NODESC_DROPS 54 +#define MC_CMD_MAC_RX_LANES01_CHAR_ERR 55 +#define MC_CMD_MAC_RX_LANES23_CHAR_ERR 56 +#define MC_CMD_MAC_RX_LANES01_DISP_ERR 57 +#define MC_CMD_MAC_RX_LANES23_DISP_ERR 58 +#define MC_CMD_MAC_RX_MATCH_FAULT 59 +/* Insert new members here. */ +#define MC_CMD_MAC_GENERATION_END 60 +#define MC_CMD_MAC_NSTATS (MC_CMD_MAC_GENERATION_END+1) + +/* MC_CMD_MAC_STATS: + * Get unified GMAC/XMAC statistics + * + * This call returns unified statistics maintained by the MC as it + * switches between the GMAC and XMAC. The MC will write out all + * supported stats. The driver should zero initialise the buffer to + * guarantee consistent results. + * + * Locks required: None + * Returns: 0 + * Response methods: shared memory, event + */ +#define MC_CMD_MAC_STATS 0x2e +#define MC_CMD_MAC_STATS_IN_LEN 16 +#define MC_CMD_MAC_STATS_IN_DMA_ADDR_LO_OFST 0 +#define MC_CMD_MAC_STATS_IN_DMA_ADDR_HI_OFST 4 +#define MC_CMD_MAC_STATS_IN_CMD_OFST 8 +#define MC_CMD_MAC_STATS_CMD_DMA_LBN 0 +#define MC_CMD_MAC_STATS_CMD_DMA_WIDTH 1 +#define MC_CMD_MAC_STATS_CMD_CLEAR_LBN 1 +#define MC_CMD_MAC_STATS_CMD_CLEAR_WIDTH 1 +#define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_LBN 2 +#define MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE_WIDTH 1 +/* Fields only relevent when PERIODIC_CHANGE is set */ +#define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_LBN 3 +#define MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE_WIDTH 1 +#define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_LBN 4 +#define MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR_WIDTH 1 +#define MC_CMD_MAC_STATS_CMD_PERIOD_MS_LBN 16 +#define MC_CMD_MAC_STATS_CMD_PERIOD_MS_WIDTH 16 +#define MC_CMD_MAC_STATS_IN_DMA_LEN_OFST 12 + +#define MC_CMD_MAC_STATS_OUT_LEN 0 + +/* Callisto flags */ +#define MC_CMD_SFT9001_ROBUST_LBN 0 +#define MC_CMD_SFT9001_ROBUST_WIDTH 1 +#define MC_CMD_SFT9001_SHORT_REACH_LBN 1 +#define MC_CMD_SFT9001_SHORT_REACH_WIDTH 1 + +/* MC_CMD_SFT9001_GET: + * Read current callisto specific setting + * + * Locks required: None + * Returns: 0, ETIME + */ +#define MC_CMD_SFT9001_GET 0x30 +#define MC_CMD_SFT9001_GET_IN_LEN 0 +#define MC_CMD_SFT9001_GET_OUT_LEN 4 +#define MC_CMD_SFT9001_GET_OUT_FLAGS_OFST 0 + +/* MC_CMD_SFT9001_SET: + * Write current callisto specific setting + * + * Locks required: None + * Returns: 0, ETIME, EINVAL + */ +#define MC_CMD_SFT9001_SET 0x31 +#define MC_CMD_SFT9001_SET_IN_LEN 4 +#define MC_CMD_SFT9001_SET_IN_FLAGS_OFST 0 +#define MC_CMD_SFT9001_SET_OUT_LEN 0 + + +/* MC_CMD_WOL_FILTER_SET: + * Set a WoL filter + * + * Locks required: None + * Returns: 0, EBUSY, EINVAL, ENOSYS + */ +#define MC_CMD_WOL_FILTER_SET 0x32 +#define MC_CMD_WOL_FILTER_SET_IN_LEN 192 /* 190 rounded up to a word */ +#define MC_CMD_WOL_FILTER_SET_IN_FILTER_MODE_OFST 0 +#define MC_CMD_WOL_FILTER_SET_IN_WOL_TYPE_OFST 4 + +/* There is a union at offset 8, following defines overlap due to + * this */ +#define MC_CMD_WOL_FILTER_SET_IN_DATA_OFST 8 + +#define MC_CMD_WOL_FILTER_SET_IN_MAGIC_MAC_OFST \ + MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + +#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_SRC_IP_OFST \ + MC_CMD_WOL_FILTER_SET_IN_DATA_OFST +#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_DST_IP_OFST \ + (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 4) +#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_SRC_PORT_OFST \ + (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 8) +#define MC_CMD_WOL_FILTER_SET_IN_IPV4_SYN_DST_PORT_OFST \ + (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 10) + +#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_SRC_IP_OFST \ + MC_CMD_WOL_FILTER_SET_IN_DATA_OFST +#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_DST_IP_OFST \ + (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 16) +#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_SRC_PORT_OFST \ + (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 32) +#define MC_CMD_WOL_FILTER_SET_IN_IPV6_SYN_DST_PORT_OFST \ + (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 34) + +#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_MASK_OFST \ + MC_CMD_WOL_FILTER_SET_IN_DATA_OFST +#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_OFST \ + (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 48) +#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LEN_OFST \ + (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 176) +#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER3_OFST \ + (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 177) +#define MC_CMD_WOL_FILTER_SET_IN_BITMAP_LAYER4_OFST \ + (MC_CMD_WOL_FILTER_SET_IN_DATA_OFST + 178) + +#define MC_CMD_WOL_FILTER_SET_OUT_LEN 4 +#define MC_CMD_WOL_FILTER_SET_OUT_FILTER_ID_OFST 0 + +/* WOL Filter types enumeration */ +#define MC_CMD_WOL_TYPE_MAGIC 0x0 + /* unused 0x1 */ +#define MC_CMD_WOL_TYPE_WIN_MAGIC 0x2 +#define MC_CMD_WOL_TYPE_IPV4_SYN 0x3 +#define MC_CMD_WOL_TYPE_IPV6_SYN 0x4 +#define MC_CMD_WOL_TYPE_BITMAP 0x5 +#define MC_CMD_WOL_TYPE_MAX 0x6 + +#define MC_CMD_FILTER_MODE_SIMPLE 0x0 +#define MC_CMD_FILTER_MODE_STRUCTURED 0xffffffff + +/* MC_CMD_WOL_FILTER_REMOVE: + * Remove a WoL filter + * + * Locks required: None + * Returns: 0, EINVAL, ENOSYS + */ +#define MC_CMD_WOL_FILTER_REMOVE 0x33 +#define MC_CMD_WOL_FILTER_REMOVE_IN_LEN 4 +#define MC_CMD_WOL_FILTER_REMOVE_IN_FILTER_ID_OFST 0 +#define MC_CMD_WOL_FILTER_REMOVE_OUT_LEN 0 + + +/* MC_CMD_WOL_FILTER_RESET: + * Reset (i.e. remove all) WoL filters + * + * Locks required: None + * Returns: 0, ENOSYS + */ +#define MC_CMD_WOL_FILTER_RESET 0x34 +#define MC_CMD_WOL_FILTER_RESET_IN_LEN 0 +#define MC_CMD_WOL_FILTER_RESET_OUT_LEN 0 + +/* MC_CMD_SET_MCAST_HASH: + * Set the MCASH hash value without otherwise + * reconfiguring the MAC + */ +#define MC_CMD_SET_MCAST_HASH 0x35 +#define MC_CMD_SET_MCAST_HASH_IN_LEN 32 +#define MC_CMD_SET_MCAST_HASH_IN_HASH0_OFST 0 +#define MC_CMD_SET_MCAST_HASH_IN_HASH1_OFST 16 +#define MC_CMD_SET_MCAST_HASH_OUT_LEN 0 + +/* MC_CMD_NVRAM_TYPES: + * Return bitfield indicating available types of virtual NVRAM partitions + * + * Locks required: none + * Returns: 0 + */ +#define MC_CMD_NVRAM_TYPES 0x36 +#define MC_CMD_NVRAM_TYPES_IN_LEN 0 +#define MC_CMD_NVRAM_TYPES_OUT_LEN 4 +#define MC_CMD_NVRAM_TYPES_OUT_TYPES_OFST 0 + +/* Supported NVRAM types */ +#define MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO 0 +#define MC_CMD_NVRAM_TYPE_MC_FW 1 +#define MC_CMD_NVRAM_TYPE_MC_FW_BACKUP 2 +#define MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 3 +#define MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1 4 +#define MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0 5 +#define MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1 6 +#define MC_CMD_NVRAM_TYPE_EXP_ROM 7 +#define MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0 8 +#define MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1 9 +#define MC_CMD_NVRAM_TYPE_PHY_PORT0 10 +#define MC_CMD_NVRAM_TYPE_PHY_PORT1 11 +#define MC_CMD_NVRAM_TYPE_LOG 12 + +/* MC_CMD_NVRAM_INFO: + * Read info about a virtual NVRAM partition + * + * Locks required: none + * Returns: 0, EINVAL (bad type) + */ +#define MC_CMD_NVRAM_INFO 0x37 +#define MC_CMD_NVRAM_INFO_IN_LEN 4 +#define MC_CMD_NVRAM_INFO_IN_TYPE_OFST 0 +#define MC_CMD_NVRAM_INFO_OUT_LEN 24 +#define MC_CMD_NVRAM_INFO_OUT_TYPE_OFST 0 +#define MC_CMD_NVRAM_INFO_OUT_SIZE_OFST 4 +#define MC_CMD_NVRAM_INFO_OUT_ERASESIZE_OFST 8 +#define MC_CMD_NVRAM_INFO_OUT_FLAGS_OFST 12 +#define MC_CMD_NVRAM_PROTECTED_LBN 0 +#define MC_CMD_NVRAM_PROTECTED_WIDTH 1 +#define MC_CMD_NVRAM_INFO_OUT_PHYSDEV_OFST 16 +#define MC_CMD_NVRAM_INFO_OUT_PHYSADDR_OFST 20 + +/* MC_CMD_NVRAM_UPDATE_START: + * Start a group of update operations on a virtual NVRAM partition + * + * Locks required: PHY_LOCK if type==*PHY* + * Returns: 0, EINVAL (bad type), EACCES (if PHY_LOCK required and not held) + */ +#define MC_CMD_NVRAM_UPDATE_START 0x38 +#define MC_CMD_NVRAM_UPDATE_START_IN_LEN 4 +#define MC_CMD_NVRAM_UPDATE_START_IN_TYPE_OFST 0 +#define MC_CMD_NVRAM_UPDATE_START_OUT_LEN 0 + +/* MC_CMD_NVRAM_READ: + * Read data from a virtual NVRAM partition + * + * Locks required: PHY_LOCK if type==*PHY* + * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) + */ +#define MC_CMD_NVRAM_READ 0x39 +#define MC_CMD_NVRAM_READ_IN_LEN 12 +#define MC_CMD_NVRAM_READ_IN_TYPE_OFST 0 +#define MC_CMD_NVRAM_READ_IN_OFFSET_OFST 4 +#define MC_CMD_NVRAM_READ_IN_LENGTH_OFST 8 +#define MC_CMD_NVRAM_READ_OUT_LEN(_read_bytes) (_read_bytes) +#define MC_CMD_NVRAM_READ_OUT_READ_BUFFER_OFST 0 + +/* MC_CMD_NVRAM_WRITE: + * Write data to a virtual NVRAM partition + * + * Locks required: PHY_LOCK if type==*PHY* + * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) + */ +#define MC_CMD_NVRAM_WRITE 0x3a +#define MC_CMD_NVRAM_WRITE_IN_TYPE_OFST 0 +#define MC_CMD_NVRAM_WRITE_IN_OFFSET_OFST 4 +#define MC_CMD_NVRAM_WRITE_IN_LENGTH_OFST 8 +#define MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_OFST 12 +#define MC_CMD_NVRAM_WRITE_IN_LEN(_write_bytes) (12 + _write_bytes) +#define MC_CMD_NVRAM_WRITE_OUT_LEN 0 + +/* MC_CMD_NVRAM_ERASE: + * Erase sector(s) from a virtual NVRAM partition + * + * Locks required: PHY_LOCK if type==*PHY* + * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) + */ +#define MC_CMD_NVRAM_ERASE 0x3b +#define MC_CMD_NVRAM_ERASE_IN_LEN 12 +#define MC_CMD_NVRAM_ERASE_IN_TYPE_OFST 0 +#define MC_CMD_NVRAM_ERASE_IN_OFFSET_OFST 4 +#define MC_CMD_NVRAM_ERASE_IN_LENGTH_OFST 8 +#define MC_CMD_NVRAM_ERASE_OUT_LEN 0 + +/* MC_CMD_NVRAM_UPDATE_FINISH: + * Finish a group of update operations on a virtual NVRAM partition + * + * Locks required: PHY_LOCK if type==*PHY* + * Returns: 0, EINVAL (bad type/offset/length), EACCES (if PHY_LOCK required and not held) + */ +#define MC_CMD_NVRAM_UPDATE_FINISH 0x3c +#define MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN 4 +#define MC_CMD_NVRAM_UPDATE_FINISH_IN_TYPE_OFST 0 +#define MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN 0 + +/* MC_CMD_REBOOT: + * Reboot the MC. The AFTER_ASSERTION flag is intended to be used + * when the driver notices an assertion failure, to allow two ports to + * both recover (semi-)gracefully. + * + * Locks required: NONE + * Returns: Nothing. You get back a response with ERR=1, DATALEN=0 + */ +#define MC_CMD_REBOOT 0x3d +#define MC_CMD_REBOOT_IN_LEN 4 +#define MC_CMD_REBOOT_IN_FLAGS_OFST 0 +#define MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION 1 +#define MC_CMD_REBOOT_OUT_LEN 0 + +/* MC_CMD_SCHEDINFO: + * Request scheduler info. from the MC. + * + * Locks required: NONE + * Returns: An array of (timeslice,maximum overrun), one for each thread, + * in ascending order of thread address.s + */ +#define MC_CMD_SCHEDINFO 0x3e +#define MC_CMD_SCHEDINFO_IN_LEN 0 + + +/* MC_CMD_SET_REBOOT_MODE: (debug) + * Set the mode for the next MC reboot. + * + * Locks required: NONE + * + * Sets the reboot mode to the specified value. Returns the old mode. + */ +#define MC_CMD_REBOOT_MODE 0x3f +#define MC_CMD_REBOOT_MODE_IN_LEN 4 +#define MC_CMD_REBOOT_MODE_IN_VALUE_OFST 0 +#define MC_CMD_REBOOT_MODE_OUT_LEN 4 +#define MC_CMD_REBOOT_MODE_OUT_VALUE_OFST 0 +#define MC_CMD_REBOOT_MODE_NORMAL 0 +#define MC_CMD_REBOOT_MODE_SNAPPER 3 + +/* MC_CMD_DEBUG_LOG: + * Null request/response command (debug) + * - sequence number is always zero + * - only supported on the UART interface + * (the same set of bytes is delivered as an + * event over PCI) + */ +#define MC_CMD_DEBUG_LOG 0x40 +#define MC_CMD_DEBUG_LOG_IN_LEN 0 +#define MC_CMD_DEBUG_LOG_OUT_LEN 0 + +/* Generic sensor enumeration. Note that a dual port NIC + * will EITHER expose PHY_COMMON_TEMP OR PHY0_TEMP and + * PHY1_TEMP depending on whether there is a single sensor + * in the vicinity of the two port, or one per port. + */ +#define MC_CMD_SENSOR_CONTROLLER_TEMP 0 /* degC */ +#define MC_CMD_SENSOR_PHY_COMMON_TEMP 1 /* degC */ +#define MC_CMD_SENSOR_CONTROLLER_COOLING 2 /* bool */ +#define MC_CMD_SENSOR_PHY0_TEMP 3 /* degC */ +#define MC_CMD_SENSOR_PHY0_COOLING 4 /* bool */ +#define MC_CMD_SENSOR_PHY1_TEMP 5 /* degC */ +#define MC_CMD_SENSOR_PHY1_COOLING 6 /* bool */ +#define MC_CMD_SENSOR_IN_1V0 7 /* mV */ +#define MC_CMD_SENSOR_IN_1V2 8 /* mV */ +#define MC_CMD_SENSOR_IN_1V8 9 /* mV */ +#define MC_CMD_SENSOR_IN_2V5 10 /* mV */ +#define MC_CMD_SENSOR_IN_3V3 11 /* mV */ +#define MC_CMD_SENSOR_IN_12V0 12 /* mV */ + + +/* Sensor state */ +#define MC_CMD_SENSOR_STATE_OK 0 +#define MC_CMD_SENSOR_STATE_WARNING 1 +#define MC_CMD_SENSOR_STATE_FATAL 2 +#define MC_CMD_SENSOR_STATE_BROKEN 3 + +/* MC_CMD_SENSOR_INFO: + * Returns information about every available sensor. + * + * Each sensor has a single (16bit) value, and a corresponding state. + * The mapping between value and sensor is nominally determined by the + * MC, but in practise is implemented as zero (BROKEN), one (TEMPERATURE), + * or two (VOLTAGE) ranges per sensor per state. + * + * This call returns a mask (32bit) of the sensors that are supported + * by this platform, then an array (indexed by MC_CMD_SENSOR) of byte + * offsets to the per-sensor arrays. Each sensor array has four 16bit + * numbers, min1, max1, min2, max2. + * + * Locks required: None + * Returns: 0 + */ +#define MC_CMD_SENSOR_INFO 0x41 +#define MC_CMD_SENSOR_INFO_IN_LEN 0 +#define MC_CMD_SENSOR_INFO_OUT_MASK_OFST 0 +#define MC_CMD_SENSOR_INFO_OUT_OFFSET_OFST(_x) \ + (4 + (_x)) +#define MC_CMD_SENSOR_INFO_OUT_MIN1_OFST(_ofst) \ + ((_ofst) + 0) +#define MC_CMD_SENSOR_INFO_OUT_MAX1_OFST(_ofst) \ + ((_ofst) + 2) +#define MC_CMD_SENSOR_INFO_OUT_MIN2_OFST(_ofst) \ + ((_ofst) + 4) +#define MC_CMD_SENSOR_INFO_OUT_MAX2_OFST(_ofst) \ + ((_ofst) + 6) + +/* MC_CMD_READ_SENSORS + * Returns the current (value, state) for each sensor + * + * Returns the current (value, state) [each 16bit] of each sensor supported by + * this board, by DMA'ing a sparse array (indexed by the sensor type) into host + * memory. + * + * The MC will send a SENSOREVT event every time any sensor changes state. The + * driver is responsible for ensuring that it doesn't miss any events. The board + * will function normally if all sensors are in STATE_OK or state_WARNING. + * Otherwise the board should not be expected to function. + */ +#define MC_CMD_READ_SENSORS 0x42 +#define MC_CMD_READ_SENSORS_IN_LEN 8 +#define MC_CMD_READ_SENSORS_IN_DMA_ADDR_LO_OFST 0 +#define MC_CMD_READ_SENSORS_IN_DMA_ADDR_HI_OFST 4 +#define MC_CMD_READ_SENSORS_OUT_LEN 0 + + +/* MC_CMD_GET_PHY_STATE: + * Report current state of PHY. A "zombie" PHY is a PHY that has failed to + * boot (e.g. due to missing or corrupted firmware). + * + * Locks required: None + * Return code: 0 + */ +#define MC_CMD_GET_PHY_STATE 0x43 + +#define MC_CMD_GET_PHY_STATE_IN_LEN 0 +#define MC_CMD_GET_PHY_STATE_OUT_LEN 4 +#define MC_CMD_GET_PHY_STATE_STATE_OFST 0 +/* PHY state enumeration: */ +#define MC_CMD_PHY_STATE_OK 1 +#define MC_CMD_PHY_STATE_ZOMBIE 2 + + +/* 802.1Qbb control. 8 Tx queues that map to priorities 0 - 7. Use all 1s to + * disable 802.Qbb for a given priority. */ +#define MC_CMD_SETUP_8021QBB 0x44 +#define MC_CMD_SETUP_8021QBB_IN_LEN 32 +#define MC_CMD_SETUP_8021QBB_OUT_LEN 0 +#define MC_CMD_SETUP_8021QBB_IN_TXQS_OFFST 0 + + +/* MC_CMD_WOL_FILTER_GET: + * Retrieve ID of any WoL filters + * + * Locks required: None + * Returns: 0, ENOSYS + */ +#define MC_CMD_WOL_FILTER_GET 0x45 +#define MC_CMD_WOL_FILTER_GET_IN_LEN 0 +#define MC_CMD_WOL_FILTER_GET_OUT_LEN 4 +#define MC_CMD_WOL_FILTER_GET_OUT_FILTER_ID_OFST 0 + + +/* MC_CMD_ADD_LIGHTSOUT_OFFLOAD: + * Offload a protocol to NIC for lights-out state + * + * Locks required: None + * Returns: 0, ENOSYS + */ +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD 0x46 + +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_LEN 16 +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_PROTOCOL_OFST 0 + +/* There is a union at offset 4, following defines overlap due to + * this */ +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_DATA_OFST 4 +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARPMAC_OFST 4 +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_ARPIP_OFST 10 +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSMAC_OFST 4 +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSSNIPV6_OFST 10 +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_IN_NSIPV6_OFST 26 + +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_LEN 4 +#define MC_CMD_ADD_LIGHTSOUT_OFFLOAD_OUT_FILTER_ID_OFST 0 + + +/* MC_CMD_REMOVE_LIGHTSOUT_PROTOCOL_OFFLOAD: + * Offload a protocol to NIC for lights-out state + * + * Locks required: None + * Returns: 0, ENOSYS + */ +#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD 0x47 +#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_LEN 8 +#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_OUT_LEN 0 + +#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_PROTOCOL_OFST 0 +#define MC_CMD_REMOVE_LIGHTSOUT_OFFLOAD_IN_FILTER_ID_OFST 4 + +/* Lights-out offload protocols enumeration */ +#define MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_ARP 0x1 +#define MC_CMD_LIGHTSOUT_OFFLOAD_PROTOCOL_NS 0x2 + + +/* MC_CMD_MAC_RESET_RESTORE: + * Restore MAC after block reset + * + * Locks required: None + * Returns: 0 + */ + +#define MC_CMD_MAC_RESET_RESTORE 0x48 +#define MC_CMD_MAC_RESET_RESTORE_IN_LEN 0 +#define MC_CMD_MAC_RESET_RESTORE_OUT_LEN 0 + +#endif /* MCDI_PCOL_H */ diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c new file mode 100644 index 00000000000..0e1bcc5a0d5 --- /dev/null +++ b/drivers/net/sfc/mcdi_phy.c @@ -0,0 +1,597 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +/* + * Driver for PHY related operations via MCDI. + */ + +#include "efx.h" +#include "phy.h" +#include "mcdi.h" +#include "mcdi_pcol.h" +#include "mdio_10g.h" + +struct efx_mcdi_phy_cfg { + u32 flags; + u32 type; + u32 supported_cap; + u32 channel; + u32 port; + u32 stats_mask; + u8 name[20]; + u32 media; + u32 mmd_mask; + u8 revision[20]; + u32 forced_cap; +}; + +static int +efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg) +{ + u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN]; + size_t outlen; + int rc; + + BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_IN_LEN != 0); + BUILD_BUG_ON(MC_CMD_GET_PHY_CFG_OUT_NAME_LEN != sizeof(cfg->name)); + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_PHY_CFG, NULL, 0, + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + + if (outlen < MC_CMD_GET_PHY_CFG_OUT_LEN) { + rc = -EMSGSIZE; + goto fail; + } + + cfg->flags = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_FLAGS); + cfg->type = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_TYPE); + cfg->supported_cap = + MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_SUPPORTED_CAP); + cfg->channel = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_CHANNEL); + cfg->port = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_PRT); + cfg->stats_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_STATS_MASK); + memcpy(cfg->name, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_NAME), + sizeof(cfg->name)); + cfg->media = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MEDIA_TYPE); + cfg->mmd_mask = MCDI_DWORD(outbuf, GET_PHY_CFG_OUT_MMD_MASK); + memcpy(cfg->revision, MCDI_PTR(outbuf, GET_PHY_CFG_OUT_REVISION), + sizeof(cfg->revision)); + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +static int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities, + u32 flags, u32 loopback_mode, + u32 loopback_speed) +{ + u8 inbuf[MC_CMD_SET_LINK_IN_LEN]; + int rc; + + BUILD_BUG_ON(MC_CMD_SET_LINK_OUT_LEN != 0); + + MCDI_SET_DWORD(inbuf, SET_LINK_IN_CAP, capabilities); + MCDI_SET_DWORD(inbuf, SET_LINK_IN_FLAGS, flags); + MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_MODE, loopback_mode); + MCDI_SET_DWORD(inbuf, SET_LINK_IN_LOOPBACK_SPEED, loopback_speed); + + rc = efx_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf), + NULL, 0, NULL); + if (rc) + goto fail; + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +static int efx_mcdi_loopback_modes(struct efx_nic *efx, u64 *loopback_modes) +{ + u8 outbuf[MC_CMD_GET_LOOPBACK_MODES_OUT_LEN]; + size_t outlen; + int rc; + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_LOOPBACK_MODES, NULL, 0, + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + + if (outlen < MC_CMD_GET_LOOPBACK_MODES_OUT_LEN) { + rc = -EMSGSIZE; + goto fail; + } + + *loopback_modes = MCDI_QWORD(outbuf, GET_LOOPBACK_MODES_SUGGESTED); + + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, + unsigned int prtad, unsigned int devad, u16 addr, + u16 *value_out, u32 *status_out) +{ + u8 inbuf[MC_CMD_MDIO_READ_IN_LEN]; + u8 outbuf[MC_CMD_MDIO_READ_OUT_LEN]; + size_t outlen; + int rc; + + MCDI_SET_DWORD(inbuf, MDIO_READ_IN_BUS, bus); + MCDI_SET_DWORD(inbuf, MDIO_READ_IN_PRTAD, prtad); + MCDI_SET_DWORD(inbuf, MDIO_READ_IN_DEVAD, devad); + MCDI_SET_DWORD(inbuf, MDIO_READ_IN_ADDR, addr); + + rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + + *value_out = (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE); + *status_out = MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS); + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus, + unsigned int prtad, unsigned int devad, u16 addr, + u16 value, u32 *status_out) +{ + u8 inbuf[MC_CMD_MDIO_WRITE_IN_LEN]; + u8 outbuf[MC_CMD_MDIO_WRITE_OUT_LEN]; + size_t outlen; + int rc; + + MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_BUS, bus); + MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_PRTAD, prtad); + MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_DEVAD, devad); + MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_ADDR, addr); + MCDI_SET_DWORD(inbuf, MDIO_WRITE_IN_VALUE, value); + + rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc) + goto fail; + + *status_out = MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS); + return 0; + +fail: + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return rc; +} + +static u32 mcdi_to_ethtool_cap(u32 media, u32 cap) +{ + u32 result = 0; + + switch (media) { + case MC_CMD_MEDIA_KX4: + result |= SUPPORTED_Backplane; + if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) + result |= SUPPORTED_1000baseKX_Full; + if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) + result |= SUPPORTED_10000baseKX4_Full; + break; + + case MC_CMD_MEDIA_XFP: + case MC_CMD_MEDIA_SFP_PLUS: + result |= SUPPORTED_FIBRE; + break; + + case MC_CMD_MEDIA_BASE_T: + result |= SUPPORTED_TP; + if (cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) + result |= SUPPORTED_10baseT_Half; + if (cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) + result |= SUPPORTED_10baseT_Full; + if (cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) + result |= SUPPORTED_100baseT_Half; + if (cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) + result |= SUPPORTED_100baseT_Full; + if (cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) + result |= SUPPORTED_1000baseT_Half; + if (cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) + result |= SUPPORTED_1000baseT_Full; + if (cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) + result |= SUPPORTED_10000baseT_Full; + break; + } + + if (cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) + result |= SUPPORTED_Pause; + if (cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) + result |= SUPPORTED_Asym_Pause; + if (cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) + result |= SUPPORTED_Autoneg; + + return result; +} + +static u32 ethtool_to_mcdi_cap(u32 cap) +{ + u32 result = 0; + + if (cap & SUPPORTED_10baseT_Half) + result |= (1 << MC_CMD_PHY_CAP_10HDX_LBN); + if (cap & SUPPORTED_10baseT_Full) + result |= (1 << MC_CMD_PHY_CAP_10FDX_LBN); + if (cap & SUPPORTED_100baseT_Half) + result |= (1 << MC_CMD_PHY_CAP_100HDX_LBN); + if (cap & SUPPORTED_100baseT_Full) + result |= (1 << MC_CMD_PHY_CAP_100FDX_LBN); + if (cap & SUPPORTED_1000baseT_Half) + result |= (1 << MC_CMD_PHY_CAP_1000HDX_LBN); + if (cap & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseKX_Full)) + result |= (1 << MC_CMD_PHY_CAP_1000FDX_LBN); + if (cap & (SUPPORTED_10000baseT_Full | SUPPORTED_10000baseKX4_Full)) + result |= (1 << MC_CMD_PHY_CAP_10000FDX_LBN); + if (cap & SUPPORTED_Pause) + result |= (1 << MC_CMD_PHY_CAP_PAUSE_LBN); + if (cap & SUPPORTED_Asym_Pause) + result |= (1 << MC_CMD_PHY_CAP_ASYM_LBN); + if (cap & SUPPORTED_Autoneg) + result |= (1 << MC_CMD_PHY_CAP_AN_LBN); + + return result; +} + +static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx) +{ + struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; + enum efx_phy_mode mode, supported; + u32 flags; + + /* TODO: Advertise the capabilities supported by this PHY */ + supported = 0; + if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_TXDIS_LBN)) + supported |= PHY_MODE_TX_DISABLED; + if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_LOWPOWER_LBN)) + supported |= PHY_MODE_LOW_POWER; + if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_POWEROFF_LBN)) + supported |= PHY_MODE_OFF; + + mode = efx->phy_mode & supported; + + flags = 0; + if (mode & PHY_MODE_TX_DISABLED) + flags |= (1 << MC_CMD_SET_LINK_TXDIS_LBN); + if (mode & PHY_MODE_LOW_POWER) + flags |= (1 << MC_CMD_SET_LINK_LOWPOWER_LBN); + if (mode & PHY_MODE_OFF) + flags |= (1 << MC_CMD_SET_LINK_POWEROFF_LBN); + + return flags; +} + +static u32 mcdi_to_ethtool_media(u32 media) +{ + switch (media) { + case MC_CMD_MEDIA_XAUI: + case MC_CMD_MEDIA_CX4: + case MC_CMD_MEDIA_KX4: + return PORT_OTHER; + + case MC_CMD_MEDIA_XFP: + case MC_CMD_MEDIA_SFP_PLUS: + return PORT_FIBRE; + + case MC_CMD_MEDIA_BASE_T: + return PORT_TP; + + default: + return PORT_OTHER; + } +} + +static int efx_mcdi_phy_probe(struct efx_nic *efx) +{ + struct efx_mcdi_phy_cfg *phy_cfg; + int rc; + + /* TODO: Move phy_data initialisation to + * phy_op->probe/remove, rather than init/fini */ + phy_cfg = kzalloc(sizeof(*phy_cfg), GFP_KERNEL); + if (phy_cfg == NULL) { + rc = -ENOMEM; + goto fail_alloc; + } + rc = efx_mcdi_get_phy_cfg(efx, phy_cfg); + if (rc != 0) + goto fail; + + efx->phy_type = phy_cfg->type; + + efx->mdio_bus = phy_cfg->channel; + efx->mdio.prtad = phy_cfg->port; + efx->mdio.mmds = phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22); + efx->mdio.mode_support = 0; + if (phy_cfg->mmd_mask & (1 << MC_CMD_MMD_CLAUSE22)) + efx->mdio.mode_support |= MDIO_SUPPORTS_C22; + if (phy_cfg->mmd_mask & ~(1 << MC_CMD_MMD_CLAUSE22)) + efx->mdio.mode_support |= MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + + /* Assert that we can map efx -> mcdi loopback modes */ + BUILD_BUG_ON(LOOPBACK_NONE != MC_CMD_LOOPBACK_NONE); + BUILD_BUG_ON(LOOPBACK_DATA != MC_CMD_LOOPBACK_DATA); + BUILD_BUG_ON(LOOPBACK_GMAC != MC_CMD_LOOPBACK_GMAC); + BUILD_BUG_ON(LOOPBACK_XGMII != MC_CMD_LOOPBACK_XGMII); + BUILD_BUG_ON(LOOPBACK_XGXS != MC_CMD_LOOPBACK_XGXS); + BUILD_BUG_ON(LOOPBACK_XAUI != MC_CMD_LOOPBACK_XAUI); + BUILD_BUG_ON(LOOPBACK_GMII != MC_CMD_LOOPBACK_GMII); + BUILD_BUG_ON(LOOPBACK_SGMII != MC_CMD_LOOPBACK_SGMII); + BUILD_BUG_ON(LOOPBACK_XGBR != MC_CMD_LOOPBACK_XGBR); + BUILD_BUG_ON(LOOPBACK_XFI != MC_CMD_LOOPBACK_XFI); + BUILD_BUG_ON(LOOPBACK_XAUI_FAR != MC_CMD_LOOPBACK_XAUI_FAR); + BUILD_BUG_ON(LOOPBACK_GMII_FAR != MC_CMD_LOOPBACK_GMII_FAR); + BUILD_BUG_ON(LOOPBACK_SGMII_FAR != MC_CMD_LOOPBACK_SGMII_FAR); + BUILD_BUG_ON(LOOPBACK_XFI_FAR != MC_CMD_LOOPBACK_XFI_FAR); + BUILD_BUG_ON(LOOPBACK_GPHY != MC_CMD_LOOPBACK_GPHY); + BUILD_BUG_ON(LOOPBACK_PHYXS != MC_CMD_LOOPBACK_PHYXS); + BUILD_BUG_ON(LOOPBACK_PCS != MC_CMD_LOOPBACK_PCS); + BUILD_BUG_ON(LOOPBACK_PMAPMD != MC_CMD_LOOPBACK_PMAPMD); + BUILD_BUG_ON(LOOPBACK_XPORT != MC_CMD_LOOPBACK_XPORT); + BUILD_BUG_ON(LOOPBACK_XGMII_WS != MC_CMD_LOOPBACK_XGMII_WS); + BUILD_BUG_ON(LOOPBACK_XAUI_WS != MC_CMD_LOOPBACK_XAUI_WS); + BUILD_BUG_ON(LOOPBACK_XAUI_WS_FAR != MC_CMD_LOOPBACK_XAUI_WS_FAR); + BUILD_BUG_ON(LOOPBACK_XAUI_WS_NEAR != MC_CMD_LOOPBACK_XAUI_WS_NEAR); + BUILD_BUG_ON(LOOPBACK_GMII_WS != MC_CMD_LOOPBACK_GMII_WS); + BUILD_BUG_ON(LOOPBACK_XFI_WS != MC_CMD_LOOPBACK_XFI_WS); + BUILD_BUG_ON(LOOPBACK_XFI_WS_FAR != MC_CMD_LOOPBACK_XFI_WS_FAR); + BUILD_BUG_ON(LOOPBACK_PHYXS_WS != MC_CMD_LOOPBACK_PHYXS_WS); + + rc = efx_mcdi_loopback_modes(efx, &efx->loopback_modes); + if (rc != 0) + goto fail; + /* The MC indicates that LOOPBACK_NONE is a valid loopback mode, + * but by convention we don't */ + efx->loopback_modes &= ~(1 << LOOPBACK_NONE); + + kfree(phy_cfg); + + return 0; + +fail: + kfree(phy_cfg); +fail_alloc: + return rc; +} + +static int efx_mcdi_phy_init(struct efx_nic *efx) +{ + struct efx_mcdi_phy_cfg *phy_data; + u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; + u32 caps; + int rc; + + phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); + if (phy_data == NULL) + return -ENOMEM; + + rc = efx_mcdi_get_phy_cfg(efx, phy_data); + if (rc != 0) + goto fail; + + efx->phy_data = phy_data; + + BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); + rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, + outbuf, sizeof(outbuf), NULL); + if (rc) + goto fail; + + caps = MCDI_DWORD(outbuf, GET_LINK_OUT_CAP); + if (caps & (1 << MC_CMD_PHY_CAP_AN_LBN)) + efx->link_advertising = + mcdi_to_ethtool_cap(phy_data->media, caps); + else + phy_data->forced_cap = caps; + + return 0; + +fail: + kfree(phy_data); + return rc; +} + +int efx_mcdi_phy_reconfigure(struct efx_nic *efx) +{ + struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; + u32 caps = (efx->link_advertising ? + ethtool_to_mcdi_cap(efx->link_advertising) : + phy_cfg->forced_cap); + + return efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), + efx->loopback_mode, 0); +} + +void efx_mcdi_phy_decode_link(struct efx_nic *efx, + struct efx_link_state *link_state, + u32 speed, u32 flags, u32 fcntl) +{ + switch (fcntl) { + case MC_CMD_FCNTL_AUTO: + WARN_ON(1); /* This is not a link mode */ + link_state->fc = EFX_FC_AUTO | EFX_FC_TX | EFX_FC_RX; + break; + case MC_CMD_FCNTL_BIDIR: + link_state->fc = EFX_FC_TX | EFX_FC_RX; + break; + case MC_CMD_FCNTL_RESPOND: + link_state->fc = EFX_FC_RX; + break; + default: + WARN_ON(1); + case MC_CMD_FCNTL_OFF: + link_state->fc = 0; + break; + } + + link_state->up = !!(flags & (1 << MC_CMD_GET_LINK_LINK_UP_LBN)); + link_state->fd = !!(flags & (1 << MC_CMD_GET_LINK_FULL_DUPLEX_LBN)); + link_state->speed = speed; +} + +/* Verify that the forced flow control settings (!EFX_FC_AUTO) are + * supported by the link partner. Warn the user if this isn't the case + */ +void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa) +{ + struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; + u32 rmtadv; + + /* The link partner capabilities are only relevent if the + * link supports flow control autonegotiation */ + if (~phy_cfg->supported_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) + return; + + /* If flow control autoneg is supported and enabled, then fine */ + if (efx->wanted_fc & EFX_FC_AUTO) + return; + + rmtadv = 0; + if (lpa & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) + rmtadv |= ADVERTISED_Pause; + if (lpa & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) + rmtadv |= ADVERTISED_Asym_Pause; + + if ((efx->wanted_fc & EFX_FC_TX) && rmtadv == ADVERTISED_Asym_Pause) + EFX_ERR(efx, "warning: link partner doesn't support " + "pause frames"); +} + +static bool efx_mcdi_phy_poll(struct efx_nic *efx) +{ + struct efx_link_state old_state = efx->link_state; + u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; + int rc; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + + BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); + + rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, + outbuf, sizeof(outbuf), NULL); + if (rc) { + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + efx->link_state.up = false; + } else { + efx_mcdi_phy_decode_link( + efx, &efx->link_state, + MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED), + MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS), + MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL)); + } + + return !efx_link_state_equal(&efx->link_state, &old_state); +} + +static void efx_mcdi_phy_fini(struct efx_nic *efx) +{ + struct efx_mcdi_phy_data *phy_data = efx->phy_data; + + efx->phy_data = NULL; + kfree(phy_data); +} + +static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; + u8 outbuf[MC_CMD_GET_LINK_OUT_LEN]; + int rc; + + ecmd->supported = + mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap); + ecmd->advertising = efx->link_advertising; + ecmd->speed = efx->link_state.speed; + ecmd->duplex = efx->link_state.fd; + ecmd->port = mcdi_to_ethtool_media(phy_cfg->media); + ecmd->phy_address = phy_cfg->port; + ecmd->transceiver = XCVR_INTERNAL; + ecmd->autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg); + ecmd->mdio_support = (efx->mdio.mode_support & + (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22)); + + BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); + rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, + outbuf, sizeof(outbuf), NULL); + if (rc) { + EFX_ERR(efx, "%s: failed rc=%d\n", __func__, rc); + return; + } + ecmd->lp_advertising = + mcdi_to_ethtool_cap(phy_cfg->media, + MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP)); +} + +static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data; + u32 caps; + int rc; + + if (ecmd->autoneg) { + caps = (ethtool_to_mcdi_cap(ecmd->advertising) | + 1 << MC_CMD_PHY_CAP_AN_LBN); + } else if (ecmd->duplex) { + switch (ecmd->speed) { + case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break; + case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break; + case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break; + case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break; + default: return -EINVAL; + } + } else { + switch (ecmd->speed) { + case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break; + case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break; + case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break; + default: return -EINVAL; + } + } + + rc = efx_mcdi_set_link(efx, caps, efx_get_mcdi_phy_flags(efx), + efx->loopback_mode, 0); + if (rc) + return rc; + + if (ecmd->autoneg) { + efx_link_set_advertising( + efx, ecmd->advertising | ADVERTISED_Autoneg); + phy_cfg->forced_cap = 0; + } else { + efx_link_set_advertising(efx, 0); + phy_cfg->forced_cap = caps; + } + return 0; +} + +struct efx_phy_operations efx_mcdi_phy_ops = { + .probe = efx_mcdi_phy_probe, + .init = efx_mcdi_phy_init, + .reconfigure = efx_mcdi_phy_reconfigure, + .poll = efx_mcdi_phy_poll, + .fini = efx_mcdi_phy_fini, + .get_settings = efx_mcdi_phy_get_settings, + .set_settings = efx_mcdi_phy_set_settings, + .run_tests = NULL, + .test_name = NULL, +}; diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 231e580acc9..1574e52f059 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -15,6 +15,7 @@ #include "net_driver.h" #include "mdio_10g.h" #include "workarounds.h" +#include "nic.h" unsigned efx_mdio_id_oui(u32 id) { @@ -173,7 +174,7 @@ bool efx_mdio_links_ok(struct efx_nic *efx, unsigned int mmd_mask) * of mmd's */ if (LOOPBACK_INTERNAL(efx)) return true; - else if (efx->loopback_mode == LOOPBACK_NETWORK) + else if (LOOPBACK_MASK(efx) & LOOPBACKS_WS) return false; else if (efx_phy_mode_disabled(efx->phy_mode)) return false; @@ -210,7 +211,7 @@ void efx_mdio_phy_reconfigure(struct efx_nic *efx) efx->loopback_mode == LOOPBACK_PCS); efx_mdio_set_flag(efx, MDIO_MMD_PHYXS, MDIO_CTRL1, MDIO_PHYXS_CTRL1_LOOPBACK, - efx->loopback_mode == LOOPBACK_NETWORK); + efx->loopback_mode == LOOPBACK_PHYXS_WS); } static void efx_mdio_set_mmd_lpower(struct efx_nic *efx, @@ -248,8 +249,6 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx, int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { struct ethtool_cmd prev; - bool xnp; - int reg; efx->phy_op->get_settings(efx, &prev); @@ -269,44 +268,58 @@ int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) (ecmd->advertising | SUPPORTED_Autoneg) & ~prev.supported) return -EINVAL; - xnp = (ecmd->advertising & ADVERTISED_10000baseT_Full - || EFX_WORKAROUND_13204(efx)); + efx_link_set_advertising(efx, ecmd->advertising | ADVERTISED_Autoneg); + efx_mdio_an_reconfigure(efx); + return 0; +} + +/** + * efx_mdio_an_reconfigure - Push advertising flags and restart autonegotiation + * @efx: Efx NIC + */ +void efx_mdio_an_reconfigure(struct efx_nic *efx) +{ + bool xnp = (efx->link_advertising & ADVERTISED_10000baseT_Full + || EFX_WORKAROUND_13204(efx)); + int reg; + + WARN_ON(!(efx->mdio.mmds & MDIO_DEVS_AN)); /* Set up the base page */ reg = ADVERTISE_CSMA; - if (ecmd->advertising & ADVERTISED_10baseT_Half) + if (efx->link_advertising & ADVERTISED_10baseT_Half) reg |= ADVERTISE_10HALF; - if (ecmd->advertising & ADVERTISED_10baseT_Full) + if (efx->link_advertising & ADVERTISED_10baseT_Full) reg |= ADVERTISE_10FULL; - if (ecmd->advertising & ADVERTISED_100baseT_Half) + if (efx->link_advertising & ADVERTISED_100baseT_Half) reg |= ADVERTISE_100HALF; - if (ecmd->advertising & ADVERTISED_100baseT_Full) + if (efx->link_advertising & ADVERTISED_100baseT_Full) reg |= ADVERTISE_100FULL; if (xnp) reg |= ADVERTISE_RESV; - else if (ecmd->advertising & (ADVERTISED_1000baseT_Half | - ADVERTISED_1000baseT_Full)) + else if (efx->link_advertising & (ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full)) reg |= ADVERTISE_NPAGE; - reg |= mii_advertise_flowctrl(efx->wanted_fc); + if (efx->link_advertising & ADVERTISED_Pause) + reg |= ADVERTISE_PAUSE_CAP; + if (efx->link_advertising & ADVERTISED_Asym_Pause) + reg |= ADVERTISE_PAUSE_ASYM; efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, reg); /* Set up the (extended) next page if necessary */ if (efx->phy_op->set_npage_adv) - efx->phy_op->set_npage_adv(efx, ecmd->advertising); + efx->phy_op->set_npage_adv(efx, efx->link_advertising); /* Enable and restart AN */ reg = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_CTRL1); reg |= MDIO_AN_CTRL1_ENABLE; - if (!(EFX_WORKAROUND_15195(efx) && - LOOPBACK_MASK(efx) & efx->phy_op->loopbacks)) + if (!(EFX_WORKAROUND_15195(efx) && LOOPBACK_EXTERNAL(efx))) reg |= MDIO_AN_CTRL1_RESTART; if (xnp) reg |= MDIO_AN_CTRL1_XNP; else reg &= ~MDIO_AN_CTRL1_XNP; efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg); - - return 0; } enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx) diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index 75b37f10123..f6ac9503339 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -86,6 +86,9 @@ extern void efx_mdio_set_mmds_lpower(struct efx_nic *efx, /* Set (some of) the PHY settings over MDIO */ extern int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); +/* Push advertising flags and restart autonegotiation */ +extern void efx_mdio_an_reconfigure(struct efx_nic *efx); + /* Get pause parameters from AN if available (otherwise return * requested pause parameters) */ diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index 820c233c3ea..3a464529a46 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c @@ -1,36 +1,80 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation, incorporated herein by reference. */ +#include <linux/bitops.h> #include <linux/module.h> #include <linux/mtd/mtd.h> #include <linux/delay.h> +#include <linux/rtnetlink.h> #define EFX_DRIVER_NAME "sfc_mtd" #include "net_driver.h" #include "spi.h" #include "efx.h" +#include "nic.h" +#include "mcdi.h" +#include "mcdi_pcol.h" #define EFX_SPI_VERIFY_BUF_LEN 16 +#define EFX_MCDI_CHUNK_LEN 128 -struct efx_mtd { - const struct efx_spi_device *spi; +struct efx_mtd_partition { struct mtd_info mtd; + union { + struct { + bool updating; + u8 nvram_type; + u16 fw_subtype; + } mcdi; + size_t offset; + }; + const char *type_name; char name[IFNAMSIZ + 20]; }; +struct efx_mtd_ops { + int (*read)(struct mtd_info *mtd, loff_t start, size_t len, + size_t *retlen, u8 *buffer); + int (*erase)(struct mtd_info *mtd, loff_t start, size_t len); + int (*write)(struct mtd_info *mtd, loff_t start, size_t len, + size_t *retlen, const u8 *buffer); + int (*sync)(struct mtd_info *mtd); +}; + +struct efx_mtd { + struct list_head node; + struct efx_nic *efx; + const struct efx_spi_device *spi; + const char *name; + const struct efx_mtd_ops *ops; + size_t n_parts; + struct efx_mtd_partition part[0]; +}; + +#define efx_for_each_partition(part, efx_mtd) \ + for ((part) = &(efx_mtd)->part[0]; \ + (part) != &(efx_mtd)->part[(efx_mtd)->n_parts]; \ + (part)++) + +#define to_efx_mtd_partition(mtd) \ + container_of(mtd, struct efx_mtd_partition, mtd) + +static int falcon_mtd_probe(struct efx_nic *efx); +static int siena_mtd_probe(struct efx_nic *efx); + /* SPI utilities */ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) { const struct efx_spi_device *spi = efx_mtd->spi; - struct efx_nic *efx = spi->efx; + struct efx_nic *efx = efx_mtd->efx; u8 status; int rc, i; @@ -39,7 +83,7 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) __set_current_state(uninterruptible ? TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); - rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, + rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); if (rc) return rc; @@ -52,32 +96,35 @@ static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) return -ETIMEDOUT; } -static int efx_spi_unlock(const struct efx_spi_device *spi) +static int +efx_spi_unlock(struct efx_nic *efx, const struct efx_spi_device *spi) { const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 | SPI_STATUS_BP0); u8 status; int rc; - rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); + rc = falcon_spi_cmd(efx, spi, SPI_RDSR, -1, NULL, + &status, sizeof(status)); if (rc) return rc; if (!(status & unlock_mask)) return 0; /* already unlocked */ - rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); if (rc) return rc; - rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0); + rc = falcon_spi_cmd(efx, spi, SPI_SST_EWSR, -1, NULL, NULL, 0); if (rc) return rc; status &= ~unlock_mask; - rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status)); + rc = falcon_spi_cmd(efx, spi, SPI_WRSR, -1, &status, + NULL, sizeof(status)); if (rc) return rc; - rc = falcon_spi_wait_write(spi); + rc = falcon_spi_wait_write(efx, spi); if (rc) return rc; @@ -87,6 +134,7 @@ static int efx_spi_unlock(const struct efx_spi_device *spi) static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) { const struct efx_spi_device *spi = efx_mtd->spi; + struct efx_nic *efx = efx_mtd->efx; unsigned pos, block_len; u8 empty[EFX_SPI_VERIFY_BUF_LEN]; u8 buffer[EFX_SPI_VERIFY_BUF_LEN]; @@ -98,13 +146,14 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) if (spi->erase_command == 0) return -EOPNOTSUPP; - rc = efx_spi_unlock(spi); + rc = efx_spi_unlock(efx, spi); if (rc) return rc; - rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + rc = falcon_spi_cmd(efx, spi, SPI_WREN, -1, NULL, NULL, 0); if (rc) return rc; - rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0); + rc = falcon_spi_cmd(efx, spi, spi->erase_command, start, NULL, + NULL, 0); if (rc) return rc; rc = efx_spi_slow_wait(efx_mtd, false); @@ -113,7 +162,8 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) memset(empty, 0xff, sizeof(empty)); for (pos = 0; pos < len; pos += block_len) { block_len = min(len - pos, sizeof(buffer)); - rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer); + rc = falcon_spi_read(efx, spi, start + pos, block_len, + NULL, buffer); if (rc) return rc; if (memcmp(empty, buffer, block_len)) @@ -130,140 +180,473 @@ static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) /* MTD interface */ -static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len, - size_t *retlen, u8 *buffer) +static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) { struct efx_mtd *efx_mtd = mtd->priv; + int rc; + + rc = efx_mtd->ops->erase(mtd, erase->addr, erase->len); + if (rc == 0) { + erase->state = MTD_ERASE_DONE; + } else { + erase->state = MTD_ERASE_FAILED; + erase->fail_addr = 0xffffffff; + } + mtd_erase_callback(erase); + return rc; +} + +static void efx_mtd_sync(struct mtd_info *mtd) +{ + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->efx; + int rc; + + rc = efx_mtd->ops->sync(mtd); + if (rc) + EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); +} + +static void efx_mtd_remove_partition(struct efx_mtd_partition *part) +{ + int rc; + + for (;;) { + rc = del_mtd_device(&part->mtd); + if (rc != -EBUSY) + break; + ssleep(1); + } + WARN_ON(rc); +} + +static void efx_mtd_remove_device(struct efx_mtd *efx_mtd) +{ + struct efx_mtd_partition *part; + + efx_for_each_partition(part, efx_mtd) + efx_mtd_remove_partition(part); + list_del(&efx_mtd->node); + kfree(efx_mtd); +} + +static void efx_mtd_rename_device(struct efx_mtd *efx_mtd) +{ + struct efx_mtd_partition *part; + + efx_for_each_partition(part, efx_mtd) + if (efx_nic_rev(efx_mtd->efx) >= EFX_REV_SIENA_A0) + snprintf(part->name, sizeof(part->name), + "%s %s:%02x", efx_mtd->efx->name, + part->type_name, part->mcdi.fw_subtype); + else + snprintf(part->name, sizeof(part->name), + "%s %s", efx_mtd->efx->name, + part->type_name); +} + +static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd) +{ + struct efx_mtd_partition *part; + + efx_mtd->efx = efx; + + efx_mtd_rename_device(efx_mtd); + + efx_for_each_partition(part, efx_mtd) { + part->mtd.writesize = 1; + + part->mtd.owner = THIS_MODULE; + part->mtd.priv = efx_mtd; + part->mtd.name = part->name; + part->mtd.erase = efx_mtd_erase; + part->mtd.read = efx_mtd->ops->read; + part->mtd.write = efx_mtd->ops->write; + part->mtd.sync = efx_mtd_sync; + + if (add_mtd_device(&part->mtd)) + goto fail; + } + + list_add(&efx_mtd->node, &efx->mtd_list); + return 0; + +fail: + while (part != &efx_mtd->part[0]) { + --part; + efx_mtd_remove_partition(part); + } + /* add_mtd_device() returns 1 if the MTD table is full */ + return -ENOMEM; +} + +void efx_mtd_remove(struct efx_nic *efx) +{ + struct efx_mtd *efx_mtd, *next; + + WARN_ON(efx_dev_registered(efx)); + + list_for_each_entry_safe(efx_mtd, next, &efx->mtd_list, node) + efx_mtd_remove_device(efx_mtd); +} + +void efx_mtd_rename(struct efx_nic *efx) +{ + struct efx_mtd *efx_mtd; + + ASSERT_RTNL(); + + list_for_each_entry(efx_mtd, &efx->mtd_list, node) + efx_mtd_rename_device(efx_mtd); +} + +int efx_mtd_probe(struct efx_nic *efx) +{ + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) + return siena_mtd_probe(efx); + else + return falcon_mtd_probe(efx); +} + +/* Implementation of MTD operations for Falcon */ + +static int falcon_mtd_read(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, u8 *buffer) +{ + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; const struct efx_spi_device *spi = efx_mtd->spi; - struct efx_nic *efx = spi->efx; + struct efx_nic *efx = efx_mtd->efx; int rc; rc = mutex_lock_interruptible(&efx->spi_lock); if (rc) return rc; - rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start, - len, retlen, buffer); + rc = falcon_spi_read(efx, spi, part->offset + start, len, + retlen, buffer); mutex_unlock(&efx->spi_lock); return rc; } -static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) +static int falcon_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) { + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); struct efx_mtd *efx_mtd = mtd->priv; - struct efx_nic *efx = efx_mtd->spi->efx; + struct efx_nic *efx = efx_mtd->efx; int rc; rc = mutex_lock_interruptible(&efx->spi_lock); if (rc) return rc; - rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr, - erase->len); + rc = efx_spi_erase(efx_mtd, part->offset + start, len); mutex_unlock(&efx->spi_lock); - - if (rc == 0) { - erase->state = MTD_ERASE_DONE; - } else { - erase->state = MTD_ERASE_FAILED; - erase->fail_addr = 0xffffffff; - } - mtd_erase_callback(erase); return rc; } -static int efx_mtd_write(struct mtd_info *mtd, loff_t start, - size_t len, size_t *retlen, const u8 *buffer) +static int falcon_mtd_write(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, const u8 *buffer) { + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); struct efx_mtd *efx_mtd = mtd->priv; const struct efx_spi_device *spi = efx_mtd->spi; - struct efx_nic *efx = spi->efx; + struct efx_nic *efx = efx_mtd->efx; int rc; rc = mutex_lock_interruptible(&efx->spi_lock); if (rc) return rc; - rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start, - len, retlen, buffer); + rc = falcon_spi_write(efx, spi, part->offset + start, len, + retlen, buffer); mutex_unlock(&efx->spi_lock); return rc; } -static void efx_mtd_sync(struct mtd_info *mtd) +static int falcon_mtd_sync(struct mtd_info *mtd) { struct efx_mtd *efx_mtd = mtd->priv; - struct efx_nic *efx = efx_mtd->spi->efx; + struct efx_nic *efx = efx_mtd->efx; int rc; mutex_lock(&efx->spi_lock); rc = efx_spi_slow_wait(efx_mtd, true); mutex_unlock(&efx->spi_lock); + return rc; +} + +static struct efx_mtd_ops falcon_mtd_ops = { + .read = falcon_mtd_read, + .erase = falcon_mtd_erase, + .write = falcon_mtd_write, + .sync = falcon_mtd_sync, +}; + +static int falcon_mtd_probe(struct efx_nic *efx) +{ + struct efx_spi_device *spi = efx->spi_flash; + struct efx_mtd *efx_mtd; + int rc; + + ASSERT_RTNL(); + if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) + return -ENODEV; + + efx_mtd = kzalloc(sizeof(*efx_mtd) + sizeof(efx_mtd->part[0]), + GFP_KERNEL); + if (!efx_mtd) + return -ENOMEM; + + efx_mtd->spi = spi; + efx_mtd->name = "flash"; + efx_mtd->ops = &falcon_mtd_ops; + + efx_mtd->n_parts = 1; + efx_mtd->part[0].mtd.type = MTD_NORFLASH; + efx_mtd->part[0].mtd.flags = MTD_CAP_NORFLASH; + efx_mtd->part[0].mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; + efx_mtd->part[0].mtd.erasesize = spi->erase_size; + efx_mtd->part[0].offset = FALCON_FLASH_BOOTCODE_START; + efx_mtd->part[0].type_name = "sfc_flash_bootrom"; + + rc = efx_mtd_probe_device(efx, efx_mtd); if (rc) - EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); - return; + kfree(efx_mtd); + return rc; } -void efx_mtd_remove(struct efx_nic *efx) +/* Implementation of MTD operations for Siena */ + +static int siena_mtd_read(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, u8 *buffer) { - if (efx->spi_flash && efx->spi_flash->mtd) { - struct efx_mtd *efx_mtd = efx->spi_flash->mtd; - int rc; - - for (;;) { - rc = del_mtd_device(&efx_mtd->mtd); - if (rc != -EBUSY) - break; - ssleep(1); - } - WARN_ON(rc); - kfree(efx_mtd); + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->efx; + loff_t offset = start; + loff_t end = min_t(loff_t, start + len, mtd->size); + size_t chunk; + int rc = 0; + + while (offset < end) { + chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); + rc = efx_mcdi_nvram_read(efx, part->mcdi.nvram_type, offset, + buffer, chunk); + if (rc) + goto out; + offset += chunk; + buffer += chunk; } +out: + *retlen = offset - start; + return rc; } -void efx_mtd_rename(struct efx_nic *efx) +static int siena_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) { - if (efx->spi_flash && efx->spi_flash->mtd) { - struct efx_mtd *efx_mtd = efx->spi_flash->mtd; - snprintf(efx_mtd->name, sizeof(efx_mtd->name), - "%s sfc_flash_bootrom", efx->name); + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->efx; + loff_t offset = start & ~((loff_t)(mtd->erasesize - 1)); + loff_t end = min_t(loff_t, start + len, mtd->size); + size_t chunk = part->mtd.erasesize; + int rc = 0; + + if (!part->mcdi.updating) { + rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type); + if (rc) + goto out; + part->mcdi.updating = 1; + } + + /* The MCDI interface can in fact do multiple erase blocks at once; + * but erasing may be slow, so we make multiple calls here to avoid + * tripping the MCDI RPC timeout. */ + while (offset < end) { + rc = efx_mcdi_nvram_erase(efx, part->mcdi.nvram_type, offset, + chunk); + if (rc) + goto out; + offset += chunk; } +out: + return rc; } -int efx_mtd_probe(struct efx_nic *efx) +static int siena_mtd_write(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, const u8 *buffer) { - struct efx_spi_device *spi = efx->spi_flash; - struct efx_mtd *efx_mtd; + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->efx; + loff_t offset = start; + loff_t end = min_t(loff_t, start + len, mtd->size); + size_t chunk; + int rc = 0; + + if (!part->mcdi.updating) { + rc = efx_mcdi_nvram_update_start(efx, part->mcdi.nvram_type); + if (rc) + goto out; + part->mcdi.updating = 1; + } - if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) + while (offset < end) { + chunk = min_t(size_t, end - offset, EFX_MCDI_CHUNK_LEN); + rc = efx_mcdi_nvram_write(efx, part->mcdi.nvram_type, offset, + buffer, chunk); + if (rc) + goto out; + offset += chunk; + buffer += chunk; + } +out: + *retlen = offset - start; + return rc; +} + +static int siena_mtd_sync(struct mtd_info *mtd) +{ + struct efx_mtd_partition *part = to_efx_mtd_partition(mtd); + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->efx; + int rc = 0; + + if (part->mcdi.updating) { + part->mcdi.updating = 0; + rc = efx_mcdi_nvram_update_finish(efx, part->mcdi.nvram_type); + } + + return rc; +} + +static struct efx_mtd_ops siena_mtd_ops = { + .read = siena_mtd_read, + .erase = siena_mtd_erase, + .write = siena_mtd_write, + .sync = siena_mtd_sync, +}; + +struct siena_nvram_type_info { + int port; + const char *name; +}; + +static struct siena_nvram_type_info siena_nvram_types[] = { + [MC_CMD_NVRAM_TYPE_DISABLED_CALLISTO] = { 0, "sfc_dummy_phy" }, + [MC_CMD_NVRAM_TYPE_MC_FW] = { 0, "sfc_mcfw" }, + [MC_CMD_NVRAM_TYPE_MC_FW_BACKUP] = { 0, "sfc_mcfw_backup" }, + [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0] = { 0, "sfc_static_cfg" }, + [MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1] = { 1, "sfc_static_cfg" }, + [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0] = { 0, "sfc_dynamic_cfg" }, + [MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1] = { 1, "sfc_dynamic_cfg" }, + [MC_CMD_NVRAM_TYPE_EXP_ROM] = { 0, "sfc_exp_rom" }, + [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT0] = { 0, "sfc_exp_rom_cfg" }, + [MC_CMD_NVRAM_TYPE_EXP_ROM_CFG_PORT1] = { 1, "sfc_exp_rom_cfg" }, + [MC_CMD_NVRAM_TYPE_PHY_PORT0] = { 0, "sfc_phy_fw" }, + [MC_CMD_NVRAM_TYPE_PHY_PORT1] = { 1, "sfc_phy_fw" }, +}; + +static int siena_mtd_probe_partition(struct efx_nic *efx, + struct efx_mtd *efx_mtd, + unsigned int part_id, + unsigned int type) +{ + struct efx_mtd_partition *part = &efx_mtd->part[part_id]; + struct siena_nvram_type_info *info; + size_t size, erase_size; + bool protected; + int rc; + + if (type >= ARRAY_SIZE(siena_nvram_types)) return -ENODEV; - efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL); + info = &siena_nvram_types[type]; + + if (info->port != efx_port_num(efx)) + return -ENODEV; + + rc = efx_mcdi_nvram_info(efx, type, &size, &erase_size, &protected); + if (rc) + return rc; + if (protected) + return -ENODEV; /* hide it */ + + part->mcdi.nvram_type = type; + part->type_name = info->name; + + part->mtd.type = MTD_NORFLASH; + part->mtd.flags = MTD_CAP_NORFLASH; + part->mtd.size = size; + part->mtd.erasesize = erase_size; + + return 0; +} + +static int siena_mtd_get_fw_subtypes(struct efx_nic *efx, + struct efx_mtd *efx_mtd) +{ + struct efx_mtd_partition *part; + uint16_t fw_subtype_list[MC_CMD_GET_BOARD_CFG_OUT_FW_SUBTYPE_LIST_LEN / + sizeof(uint16_t)]; + int rc; + + rc = efx_mcdi_get_board_cfg(efx, NULL, fw_subtype_list); + if (rc) + return rc; + + efx_for_each_partition(part, efx_mtd) + part->mcdi.fw_subtype = fw_subtype_list[part->mcdi.nvram_type]; + + return 0; +} + +static int siena_mtd_probe(struct efx_nic *efx) +{ + struct efx_mtd *efx_mtd; + int rc = -ENODEV; + u32 nvram_types; + unsigned int type; + + ASSERT_RTNL(); + + rc = efx_mcdi_nvram_types(efx, &nvram_types); + if (rc) + return rc; + + efx_mtd = kzalloc(sizeof(*efx_mtd) + + hweight32(nvram_types) * sizeof(efx_mtd->part[0]), + GFP_KERNEL); if (!efx_mtd) return -ENOMEM; - efx_mtd->spi = spi; - spi->mtd = efx_mtd; - - efx_mtd->mtd.type = MTD_NORFLASH; - efx_mtd->mtd.flags = MTD_CAP_NORFLASH; - efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; - efx_mtd->mtd.erasesize = spi->erase_size; - efx_mtd->mtd.writesize = 1; - efx_mtd_rename(efx); - - efx_mtd->mtd.owner = THIS_MODULE; - efx_mtd->mtd.priv = efx_mtd; - efx_mtd->mtd.name = efx_mtd->name; - efx_mtd->mtd.erase = efx_mtd_erase; - efx_mtd->mtd.read = efx_mtd_read; - efx_mtd->mtd.write = efx_mtd_write; - efx_mtd->mtd.sync = efx_mtd_sync; - - if (add_mtd_device(&efx_mtd->mtd)) { - kfree(efx_mtd); - spi->mtd = NULL; - /* add_mtd_device() returns 1 if the MTD table is full */ - return -ENOMEM; + efx_mtd->name = "Siena NVRAM manager"; + + efx_mtd->ops = &siena_mtd_ops; + + type = 0; + efx_mtd->n_parts = 0; + + while (nvram_types != 0) { + if (nvram_types & 1) { + rc = siena_mtd_probe_partition(efx, efx_mtd, + efx_mtd->n_parts, type); + if (rc == 0) + efx_mtd->n_parts++; + else if (rc != -ENODEV) + goto fail; + } + type++; + nvram_types >>= 1; } - return 0; + rc = siena_mtd_get_fw_subtypes(efx, efx_mtd); + if (rc) + goto fail; + + rc = efx_mtd_probe_device(efx, efx_mtd); +fail: + if (rc) + kfree(efx_mtd); + return rc; } + diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index ac808d5f24a..34c381f009b 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2008 Solarflare Communications Inc. + * Copyright 2005-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -38,7 +38,7 @@ #ifndef EFX_DRIVER_NAME #define EFX_DRIVER_NAME "sfc" #endif -#define EFX_DRIVER_VERSION "2.3" +#define EFX_DRIVER_VERSION "3.0" #ifdef EFX_ENABLE_DEBUG #define EFX_BUG_ON_PARANOID(x) BUG_ON(x) @@ -113,6 +113,13 @@ struct efx_special_buffer { int entries; }; +enum efx_flush_state { + FLUSH_NONE, + FLUSH_PENDING, + FLUSH_FAILED, + FLUSH_DONE, +}; + /** * struct efx_tx_buffer - An Efx TX buffer * @skb: The associated socket buffer. @@ -189,7 +196,7 @@ struct efx_tx_queue { struct efx_nic *nic; struct efx_tx_buffer *buffer; struct efx_special_buffer txd; - bool flushed; + enum efx_flush_state flushed; /* Members used mainly on the completion path */ unsigned int read_count ____cacheline_aligned_in_smp; @@ -284,7 +291,7 @@ struct efx_rx_queue { struct page *buf_page; dma_addr_t buf_dma_addr; char *buf_data; - bool flushed; + enum efx_flush_state flushed; }; /** @@ -343,9 +350,9 @@ enum efx_rx_alloc_method { * @rx_alloc_push_pages: RX allocation method currently in use for pushing * descriptors * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors - * @n_rx_ip_frag_err: Count of RX IP fragment errors * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors + * @n_rx_mcast_mismatch: Count of unmatched multicast frames * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors * @n_rx_overlength: Count of RX_OVERLENGTH errors * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun @@ -373,9 +380,9 @@ struct efx_channel { int rx_alloc_push_pages; unsigned n_rx_tobe_disc; - unsigned n_rx_ip_frag_err; unsigned n_rx_ip_hdr_chksum_err; unsigned n_rx_tcp_udp_chksum_err; + unsigned n_rx_mcast_mismatch; unsigned n_rx_frm_trunc; unsigned n_rx_overlength; unsigned n_skbuff_leaks; @@ -421,19 +428,6 @@ enum efx_int_mode { }; #define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI) -enum phy_type { - PHY_TYPE_NONE = 0, - PHY_TYPE_TXC43128 = 1, - PHY_TYPE_88E1111 = 2, - PHY_TYPE_SFX7101 = 3, - PHY_TYPE_QT2022C2 = 4, - PHY_TYPE_PM8358 = 6, - PHY_TYPE_SFT9001A = 8, - PHY_TYPE_QT2025C = 9, - PHY_TYPE_SFT9001B = 10, - PHY_TYPE_MAX /* Insert any new items before this */ -}; - #define EFX_IS10G(efx) ((efx)->link_state.speed == 10000) enum nic_state { @@ -476,12 +470,6 @@ enum efx_fc_type { EFX_FC_AUTO = 4, }; -/* Supported MAC bit-mask */ -enum efx_mac_type { - EFX_GMAC = 1, - EFX_XMAC = 2, -}; - /** * struct efx_link_state - Current state of the link * @up: Link is up @@ -496,55 +484,55 @@ struct efx_link_state { unsigned int speed; }; +static inline bool efx_link_state_equal(const struct efx_link_state *left, + const struct efx_link_state *right) +{ + return left->up == right->up && left->fd == right->fd && + left->fc == right->fc && left->speed == right->speed; +} + /** * struct efx_mac_operations - Efx MAC operations table * @reconfigure: Reconfigure MAC. Serialised by the mac_lock * @update_stats: Update statistics - * @irq: Hardware MAC event callback. Serialised by the mac_lock - * @poll: Poll for hardware state. Serialised by the mac_lock + * @check_fault: Check fault state. True if fault present. */ struct efx_mac_operations { - void (*reconfigure) (struct efx_nic *efx); + int (*reconfigure) (struct efx_nic *efx); void (*update_stats) (struct efx_nic *efx); - void (*irq) (struct efx_nic *efx); - void (*poll) (struct efx_nic *efx); + bool (*check_fault)(struct efx_nic *efx); }; /** * struct efx_phy_operations - Efx PHY operations table + * @probe: Probe PHY and initialise efx->mdio.mode_support, efx->mdio.mmds, + * efx->loopback_modes. * @init: Initialise PHY * @fini: Shut down PHY * @reconfigure: Reconfigure PHY (e.g. for new link parameters) - * @clear_interrupt: Clear down interrupt - * @poll: Poll for hardware state. Serialised by the mac_lock. + * @poll: Update @link_state and report whether it changed. + * Serialised by the mac_lock. * @get_settings: Get ethtool settings. Serialised by the mac_lock. * @set_settings: Set ethtool settings. Serialised by the mac_lock. * @set_npage_adv: Set abilities advertised in (Extended) Next Page * (only needed where AN bit is set in mmds) - * @num_tests: Number of PHY-specific tests/results - * @test_names: Names of the tests/results + * @test_name: Get the name of a PHY-specific test/result * @run_tests: Run tests and record results as appropriate. * Flags are the ethtool tests flags. - * @mmds: MMD presence mask - * @loopbacks: Supported loopback modes mask */ struct efx_phy_operations { - enum efx_mac_type macs; + int (*probe) (struct efx_nic *efx); int (*init) (struct efx_nic *efx); void (*fini) (struct efx_nic *efx); - void (*reconfigure) (struct efx_nic *efx); - void (*clear_interrupt) (struct efx_nic *efx); - void (*poll) (struct efx_nic *efx); + int (*reconfigure) (struct efx_nic *efx); + bool (*poll) (struct efx_nic *efx); void (*get_settings) (struct efx_nic *efx, struct ethtool_cmd *ecmd); int (*set_settings) (struct efx_nic *efx, struct ethtool_cmd *ecmd); void (*set_npage_adv) (struct efx_nic *efx, u32); - u32 num_tests; - const char *const *test_names; + const char *(*test_name) (struct efx_nic *efx, unsigned int index); int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags); - int mmds; - unsigned loopbacks; }; /** @@ -686,19 +674,20 @@ union efx_multicast_hash { * interrupt is handled. It is used by falcon_test_interrupt() * to verify that an interrupt has occurred. * @spi_flash: SPI flash device - * This field will be %NULL if no flash device is present. + * This field will be %NULL if no flash device is present (or for Siena). * @spi_eeprom: SPI EEPROM device - * This field will be %NULL if no EEPROM device is present. + * This field will be %NULL if no EEPROM device is present (or for Siena). * @spi_lock: SPI bus lock + * @mtd_list: List of MTDs attached to the NIC * @n_rx_nodesc_drop_cnt: RX no descriptor drop count * @nic_data: Hardware dependant state * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, * @port_inhibited, efx_monitor() and efx_reconfigure_port() * @port_enabled: Port enabled indicator. - * Serialises efx_stop_all(), efx_start_all(), efx_monitor(), - * efx_phy_work(), and efx_mac_work() with kernel interfaces. Safe to read - * under any one of the rtnl_lock, mac_lock, or netif_tx_lock, but all - * three must be held to modify it. + * Serialises efx_stop_all(), efx_start_all(), efx_monitor() and + * efx_mac_work() with kernel interfaces. Safe to read under any + * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must + * be held to modify it. * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock * @port_initialized: Port initialized? * @net_dev: Operating system network device. Consider holding the rtnl lock @@ -710,23 +699,23 @@ union efx_multicast_hash { * &struct net_device_stats. * @stats_buffer: DMA buffer for statistics * @stats_lock: Statistics update lock. Serialises statistics fetches - * @stats_disable_count: Nest count for disabling statistics fetches * @mac_op: MAC interface * @mac_address: Permanent MAC address * @phy_type: PHY type - * @phy_lock: PHY access lock + * @mdio_lock: MDIO lock * @phy_op: PHY interface * @phy_data: PHY private data (including PHY-specific stats) * @mdio: PHY MDIO interface + * @mdio_bus: PHY MDIO bus ID (only used by Siena) * @phy_mode: PHY operating mode. Serialised by @mac_lock. - * @mac_up: MAC link state + * @xmac_poll_required: XMAC link state needs polling + * @link_advertising: Autonegotiation advertising flags * @link_state: Current state of the link * @n_link_state_changes: Number of times the link has changed state * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. * @multicast_hash: Multicast hash table * @wanted_fc: Wanted flow control flags - * @phy_work: work item for dealing with PHY events - * @mac_work: work item for dealing with MAC events + * @mac_work: Work item for changing MAC promiscuity and multicast hash * @loopback_mode: Loopback status * @loopback_modes: Supported loopback mode bitmask * @loopback_selftest: Offline self-test private state @@ -768,14 +757,18 @@ struct efx_nic { struct efx_buffer irq_status; volatile signed int last_irq_cpu; + unsigned long irq_zero_count; struct efx_spi_device *spi_flash; struct efx_spi_device *spi_eeprom; struct mutex spi_lock; +#ifdef CONFIG_SFC_MTD + struct list_head mtd_list; +#endif unsigned n_rx_nodesc_drop_cnt; - struct falcon_nic_data *nic_data; + void *nic_data; struct mutex mac_lock; struct work_struct mac_work; @@ -792,20 +785,20 @@ struct efx_nic { struct efx_mac_stats mac_stats; struct efx_buffer stats_buffer; spinlock_t stats_lock; - unsigned int stats_disable_count; struct efx_mac_operations *mac_op; unsigned char mac_address[ETH_ALEN]; - enum phy_type phy_type; - spinlock_t phy_lock; - struct work_struct phy_work; + unsigned int phy_type; + struct mutex mdio_lock; struct efx_phy_operations *phy_op; void *phy_data; struct mdio_if_info mdio; + unsigned int mdio_bus; enum efx_phy_mode phy_mode; - bool mac_up; + bool xmac_poll_required; + u32 link_advertising; struct efx_link_state link_state; unsigned int n_link_state_changes; @@ -815,7 +808,7 @@ struct efx_nic { atomic_t rx_reset; enum efx_loopback_mode loopback_mode; - unsigned int loopback_modes; + u64 loopback_modes; void *loopback_selftest; }; @@ -834,8 +827,37 @@ static inline const char *efx_dev_name(struct efx_nic *efx) return efx_dev_registered(efx) ? efx->name : ""; } +static inline unsigned int efx_port_num(struct efx_nic *efx) +{ + return PCI_FUNC(efx->pci_dev->devfn); +} + /** * struct efx_nic_type - Efx device type definition + * @probe: Probe the controller + * @remove: Free resources allocated by probe() + * @init: Initialise the controller + * @fini: Shut down the controller + * @monitor: Periodic function for polling link state and hardware monitor + * @reset: Reset the controller hardware and possibly the PHY. This will + * be called while the controller is uninitialised. + * @probe_port: Probe the MAC and PHY + * @remove_port: Free resources allocated by probe_port() + * @prepare_flush: Prepare the hardware for flushing the DMA queues + * @update_stats: Update statistics not provided by event handling + * @start_stats: Start the regular fetching of statistics + * @stop_stats: Stop the regular fetching of statistics + * @set_id_led: Set state of identifying LED or revert to automatic function + * @push_irq_moderation: Apply interrupt moderation value + * @push_multicast_hash: Apply multicast hash table + * @reconfigure_port: Push loopback/power/txdis changes to the MAC and PHY + * @get_wol: Get WoL configuration from driver state + * @set_wol: Push WoL configuration to the NIC + * @resume_wol: Synchronise WoL state between driver and MC (e.g. after resume) + * @test_registers: Test read/write functionality of control registers + * @test_nvram: Test validity of NVRAM contents + * @default_mac_ops: efx_mac_operations to set at startup + * @revision: Hardware architecture revision * @mem_map_size: Memory BAR mapped size * @txd_ptr_tbl_base: TX descriptor ring base address * @rxd_ptr_tbl_base: RX descriptor ring base address @@ -848,20 +870,52 @@ static inline const char *efx_dev_name(struct efx_nic *efx) * from &enum efx_init_mode. * @phys_addr_channels: Number of channels with physically addressed * descriptors + * @tx_dc_base: Base address in SRAM of TX queue descriptor caches + * @rx_dc_base: Base address in SRAM of RX queue descriptor caches + * @offload_features: net_device feature flags for protocol offload + * features implemented in hardware + * @reset_world_flags: Flags for additional components covered by + * reset method RESET_TYPE_WORLD */ struct efx_nic_type { + int (*probe)(struct efx_nic *efx); + void (*remove)(struct efx_nic *efx); + int (*init)(struct efx_nic *efx); + void (*fini)(struct efx_nic *efx); + void (*monitor)(struct efx_nic *efx); + int (*reset)(struct efx_nic *efx, enum reset_type method); + int (*probe_port)(struct efx_nic *efx); + void (*remove_port)(struct efx_nic *efx); + void (*prepare_flush)(struct efx_nic *efx); + void (*update_stats)(struct efx_nic *efx); + void (*start_stats)(struct efx_nic *efx); + void (*stop_stats)(struct efx_nic *efx); + void (*set_id_led)(struct efx_nic *efx, enum efx_led_mode mode); + void (*push_irq_moderation)(struct efx_channel *channel); + void (*push_multicast_hash)(struct efx_nic *efx); + int (*reconfigure_port)(struct efx_nic *efx); + void (*get_wol)(struct efx_nic *efx, struct ethtool_wolinfo *wol); + int (*set_wol)(struct efx_nic *efx, u32 type); + void (*resume_wol)(struct efx_nic *efx); + int (*test_registers)(struct efx_nic *efx); + int (*test_nvram)(struct efx_nic *efx); + struct efx_mac_operations *default_mac_ops; + + int revision; unsigned int mem_map_size; unsigned int txd_ptr_tbl_base; unsigned int rxd_ptr_tbl_base; unsigned int buf_tbl_base; unsigned int evq_ptr_tbl_base; unsigned int evq_rptr_tbl_base; - u64 max_dma_mask; - unsigned int rx_buffer_padding; unsigned int max_interrupt_mode; unsigned int phys_addr_channels; + unsigned int tx_dc_base; + unsigned int rx_dc_base; + unsigned long offload_features; + u32 reset_world_flags; }; /************************************************************************** diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c new file mode 100644 index 00000000000..a577be22786 --- /dev/null +++ b/drivers/net/sfc/nic.c @@ -0,0 +1,1583 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/seq_file.h> +#include "net_driver.h" +#include "bitfield.h" +#include "efx.h" +#include "nic.h" +#include "regs.h" +#include "io.h" +#include "workarounds.h" + +/************************************************************************** + * + * Configurable values + * + ************************************************************************** + */ + +/* This is set to 16 for a good reason. In summary, if larger than + * 16, the descriptor cache holds more than a default socket + * buffer's worth of packets (for UDP we can only have at most one + * socket buffer's worth outstanding). This combined with the fact + * that we only get 1 TX event per descriptor cache means the NIC + * goes idle. + */ +#define TX_DC_ENTRIES 16 +#define TX_DC_ENTRIES_ORDER 1 + +#define RX_DC_ENTRIES 64 +#define RX_DC_ENTRIES_ORDER 3 + +/* RX FIFO XOFF watermark + * + * When the amount of the RX FIFO increases used increases past this + * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A) + * This also has an effect on RX/TX arbitration + */ +int efx_nic_rx_xoff_thresh = -1; +module_param_named(rx_xoff_thresh_bytes, efx_nic_rx_xoff_thresh, int, 0644); +MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold"); + +/* RX FIFO XON watermark + * + * When the amount of the RX FIFO used decreases below this + * watermark send XON. Only used if TX flow control is enabled (ethtool -A) + * This also has an effect on RX/TX arbitration + */ +int efx_nic_rx_xon_thresh = -1; +module_param_named(rx_xon_thresh_bytes, efx_nic_rx_xon_thresh, int, 0644); +MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold"); + +/* If EFX_MAX_INT_ERRORS internal errors occur within + * EFX_INT_ERROR_EXPIRE seconds, we consider the NIC broken and + * disable it. + */ +#define EFX_INT_ERROR_EXPIRE 3600 +#define EFX_MAX_INT_ERRORS 5 + +/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times + */ +#define EFX_FLUSH_INTERVAL 10 +#define EFX_FLUSH_POLL_COUNT 100 + +/* Size and alignment of special buffers (4KB) */ +#define EFX_BUF_SIZE 4096 + +/* Depth of RX flush request fifo */ +#define EFX_RX_FLUSH_COUNT 4 + +/************************************************************************** + * + * Solarstorm hardware access + * + **************************************************************************/ + +static inline void efx_write_buf_tbl(struct efx_nic *efx, efx_qword_t *value, + unsigned int index) +{ + efx_sram_writeq(efx, efx->membase + efx->type->buf_tbl_base, + value, index); +} + +/* Read the current event from the event queue */ +static inline efx_qword_t *efx_event(struct efx_channel *channel, + unsigned int index) +{ + return (((efx_qword_t *) (channel->eventq.addr)) + index); +} + +/* See if an event is present + * + * We check both the high and low dword of the event for all ones. We + * wrote all ones when we cleared the event, and no valid event can + * have all ones in either its high or low dwords. This approach is + * robust against reordering. + * + * Note that using a single 64-bit comparison is incorrect; even + * though the CPU read will be atomic, the DMA write may not be. + */ +static inline int efx_event_present(efx_qword_t *event) +{ + return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) | + EFX_DWORD_IS_ALL_ONES(event->dword[1]))); +} + +static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b, + const efx_oword_t *mask) +{ + return ((a->u64[0] ^ b->u64[0]) & mask->u64[0]) || + ((a->u64[1] ^ b->u64[1]) & mask->u64[1]); +} + +int efx_nic_test_registers(struct efx_nic *efx, + const struct efx_nic_register_test *regs, + size_t n_regs) +{ + unsigned address = 0, i, j; + efx_oword_t mask, imask, original, reg, buf; + + /* Falcon should be in loopback to isolate the XMAC from the PHY */ + WARN_ON(!LOOPBACK_INTERNAL(efx)); + + for (i = 0; i < n_regs; ++i) { + address = regs[i].address; + mask = imask = regs[i].mask; + EFX_INVERT_OWORD(imask); + + efx_reado(efx, &original, address); + + /* bit sweep on and off */ + for (j = 0; j < 128; j++) { + if (!EFX_EXTRACT_OWORD32(mask, j, j)) + continue; + + /* Test this testable bit can be set in isolation */ + EFX_AND_OWORD(reg, original, mask); + EFX_SET_OWORD32(reg, j, j, 1); + + efx_writeo(efx, ®, address); + efx_reado(efx, &buf, address); + + if (efx_masked_compare_oword(®, &buf, &mask)) + goto fail; + + /* Test this testable bit can be cleared in isolation */ + EFX_OR_OWORD(reg, original, mask); + EFX_SET_OWORD32(reg, j, j, 0); + + efx_writeo(efx, ®, address); + efx_reado(efx, &buf, address); + + if (efx_masked_compare_oword(®, &buf, &mask)) + goto fail; + } + + efx_writeo(efx, &original, address); + } + + return 0; + +fail: + EFX_ERR(efx, "wrote "EFX_OWORD_FMT" read "EFX_OWORD_FMT + " at address 0x%x mask "EFX_OWORD_FMT"\n", EFX_OWORD_VAL(reg), + EFX_OWORD_VAL(buf), address, EFX_OWORD_VAL(mask)); + return -EIO; +} + +/************************************************************************** + * + * Special buffer handling + * Special buffers are used for event queues and the TX and RX + * descriptor rings. + * + *************************************************************************/ + +/* + * Initialise a special buffer + * + * This will define a buffer (previously allocated via + * efx_alloc_special_buffer()) in the buffer table, allowing + * it to be used for event queues, descriptor rings etc. + */ +static void +efx_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) +{ + efx_qword_t buf_desc; + int index; + dma_addr_t dma_addr; + int i; + + EFX_BUG_ON_PARANOID(!buffer->addr); + + /* Write buffer descriptors to NIC */ + for (i = 0; i < buffer->entries; i++) { + index = buffer->index + i; + dma_addr = buffer->dma_addr + (i * 4096); + EFX_LOG(efx, "mapping special buffer %d at %llx\n", + index, (unsigned long long)dma_addr); + EFX_POPULATE_QWORD_3(buf_desc, + FRF_AZ_BUF_ADR_REGION, 0, + FRF_AZ_BUF_ADR_FBUF, dma_addr >> 12, + FRF_AZ_BUF_OWNER_ID_FBUF, 0); + efx_write_buf_tbl(efx, &buf_desc, index); + } +} + +/* Unmaps a buffer and clears the buffer table entries */ +static void +efx_fini_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) +{ + efx_oword_t buf_tbl_upd; + unsigned int start = buffer->index; + unsigned int end = (buffer->index + buffer->entries - 1); + + if (!buffer->entries) + return; + + EFX_LOG(efx, "unmapping special buffers %d-%d\n", + buffer->index, buffer->index + buffer->entries - 1); + + EFX_POPULATE_OWORD_4(buf_tbl_upd, + FRF_AZ_BUF_UPD_CMD, 0, + FRF_AZ_BUF_CLR_CMD, 1, + FRF_AZ_BUF_CLR_END_ID, end, + FRF_AZ_BUF_CLR_START_ID, start); + efx_writeo(efx, &buf_tbl_upd, FR_AZ_BUF_TBL_UPD); +} + +/* + * Allocate a new special buffer + * + * This allocates memory for a new buffer, clears it and allocates a + * new buffer ID range. It does not write into the buffer table. + * + * This call will allocate 4KB buffers, since 8KB buffers can't be + * used for event queues and descriptor rings. + */ +static int efx_alloc_special_buffer(struct efx_nic *efx, + struct efx_special_buffer *buffer, + unsigned int len) +{ + len = ALIGN(len, EFX_BUF_SIZE); + + buffer->addr = pci_alloc_consistent(efx->pci_dev, len, + &buffer->dma_addr); + if (!buffer->addr) + return -ENOMEM; + buffer->len = len; + buffer->entries = len / EFX_BUF_SIZE; + BUG_ON(buffer->dma_addr & (EFX_BUF_SIZE - 1)); + + /* All zeros is a potentially valid event so memset to 0xff */ + memset(buffer->addr, 0xff, len); + + /* Select new buffer ID */ + buffer->index = efx->next_buffer_table; + efx->next_buffer_table += buffer->entries; + + EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x " + "(virt %p phys %llx)\n", buffer->index, + buffer->index + buffer->entries - 1, + (u64)buffer->dma_addr, len, + buffer->addr, (u64)virt_to_phys(buffer->addr)); + + return 0; +} + +static void +efx_free_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer) +{ + if (!buffer->addr) + return; + + EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x " + "(virt %p phys %llx)\n", buffer->index, + buffer->index + buffer->entries - 1, + (u64)buffer->dma_addr, buffer->len, + buffer->addr, (u64)virt_to_phys(buffer->addr)); + + pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr, + buffer->dma_addr); + buffer->addr = NULL; + buffer->entries = 0; +} + +/************************************************************************** + * + * Generic buffer handling + * These buffers are used for interrupt status and MAC stats + * + **************************************************************************/ + +int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, + unsigned int len) +{ + buffer->addr = pci_alloc_consistent(efx->pci_dev, len, + &buffer->dma_addr); + if (!buffer->addr) + return -ENOMEM; + buffer->len = len; + memset(buffer->addr, 0, len); + return 0; +} + +void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer) +{ + if (buffer->addr) { + pci_free_consistent(efx->pci_dev, buffer->len, + buffer->addr, buffer->dma_addr); + buffer->addr = NULL; + } +} + +/************************************************************************** + * + * TX path + * + **************************************************************************/ + +/* Returns a pointer to the specified transmit descriptor in the TX + * descriptor queue belonging to the specified channel. + */ +static inline efx_qword_t * +efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index) +{ + return (((efx_qword_t *) (tx_queue->txd.addr)) + index); +} + +/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */ +static inline void efx_notify_tx_desc(struct efx_tx_queue *tx_queue) +{ + unsigned write_ptr; + efx_dword_t reg; + + write_ptr = tx_queue->write_count & EFX_TXQ_MASK; + EFX_POPULATE_DWORD_1(reg, FRF_AZ_TX_DESC_WPTR_DWORD, write_ptr); + efx_writed_page(tx_queue->efx, ®, + FR_AZ_TX_DESC_UPD_DWORD_P0, tx_queue->queue); +} + + +/* For each entry inserted into the software descriptor ring, create a + * descriptor in the hardware TX descriptor ring (in host memory), and + * write a doorbell. + */ +void efx_nic_push_buffers(struct efx_tx_queue *tx_queue) +{ + + struct efx_tx_buffer *buffer; + efx_qword_t *txd; + unsigned write_ptr; + + BUG_ON(tx_queue->write_count == tx_queue->insert_count); + + do { + write_ptr = tx_queue->write_count & EFX_TXQ_MASK; + buffer = &tx_queue->buffer[write_ptr]; + txd = efx_tx_desc(tx_queue, write_ptr); + ++tx_queue->write_count; + + /* Create TX descriptor ring entry */ + EFX_POPULATE_QWORD_4(*txd, + FSF_AZ_TX_KER_CONT, buffer->continuation, + FSF_AZ_TX_KER_BYTE_COUNT, buffer->len, + FSF_AZ_TX_KER_BUF_REGION, 0, + FSF_AZ_TX_KER_BUF_ADDR, buffer->dma_addr); + } while (tx_queue->write_count != tx_queue->insert_count); + + wmb(); /* Ensure descriptors are written before they are fetched */ + efx_notify_tx_desc(tx_queue); +} + +/* Allocate hardware resources for a TX queue */ +int efx_nic_probe_tx(struct efx_tx_queue *tx_queue) +{ + struct efx_nic *efx = tx_queue->efx; + BUILD_BUG_ON(EFX_TXQ_SIZE < 512 || EFX_TXQ_SIZE > 4096 || + EFX_TXQ_SIZE & EFX_TXQ_MASK); + return efx_alloc_special_buffer(efx, &tx_queue->txd, + EFX_TXQ_SIZE * sizeof(efx_qword_t)); +} + +void efx_nic_init_tx(struct efx_tx_queue *tx_queue) +{ + efx_oword_t tx_desc_ptr; + struct efx_nic *efx = tx_queue->efx; + + tx_queue->flushed = FLUSH_NONE; + + /* Pin TX descriptor ring */ + efx_init_special_buffer(efx, &tx_queue->txd); + + /* Push TX descriptor ring to card */ + EFX_POPULATE_OWORD_10(tx_desc_ptr, + FRF_AZ_TX_DESCQ_EN, 1, + FRF_AZ_TX_ISCSI_DDIG_EN, 0, + FRF_AZ_TX_ISCSI_HDIG_EN, 0, + FRF_AZ_TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index, + FRF_AZ_TX_DESCQ_EVQ_ID, + tx_queue->channel->channel, + FRF_AZ_TX_DESCQ_OWNER_ID, 0, + FRF_AZ_TX_DESCQ_LABEL, tx_queue->queue, + FRF_AZ_TX_DESCQ_SIZE, + __ffs(tx_queue->txd.entries), + FRF_AZ_TX_DESCQ_TYPE, 0, + FRF_BZ_TX_NON_IP_DROP_DIS, 1); + + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { + int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM; + EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum); + EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS, + !csum); + } + + efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, + tx_queue->queue); + + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) { + efx_oword_t reg; + + /* Only 128 bits in this register */ + BUILD_BUG_ON(EFX_TX_QUEUE_COUNT >= 128); + + efx_reado(efx, ®, FR_AA_TX_CHKSM_CFG); + if (tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM) + clear_bit_le(tx_queue->queue, (void *)®); + else + set_bit_le(tx_queue->queue, (void *)®); + efx_writeo(efx, ®, FR_AA_TX_CHKSM_CFG); + } +} + +static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue) +{ + struct efx_nic *efx = tx_queue->efx; + efx_oword_t tx_flush_descq; + + tx_queue->flushed = FLUSH_PENDING; + + /* Post a flush command */ + EFX_POPULATE_OWORD_2(tx_flush_descq, + FRF_AZ_TX_FLUSH_DESCQ_CMD, 1, + FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue); + efx_writeo(efx, &tx_flush_descq, FR_AZ_TX_FLUSH_DESCQ); +} + +void efx_nic_fini_tx(struct efx_tx_queue *tx_queue) +{ + struct efx_nic *efx = tx_queue->efx; + efx_oword_t tx_desc_ptr; + + /* The queue should have been flushed */ + WARN_ON(tx_queue->flushed != FLUSH_DONE); + + /* Remove TX descriptor ring from card */ + EFX_ZERO_OWORD(tx_desc_ptr); + efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base, + tx_queue->queue); + + /* Unpin TX descriptor ring */ + efx_fini_special_buffer(efx, &tx_queue->txd); +} + +/* Free buffers backing TX queue */ +void efx_nic_remove_tx(struct efx_tx_queue *tx_queue) +{ + efx_free_special_buffer(tx_queue->efx, &tx_queue->txd); +} + +/************************************************************************** + * + * RX path + * + **************************************************************************/ + +/* Returns a pointer to the specified descriptor in the RX descriptor queue */ +static inline efx_qword_t * +efx_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index) +{ + return (((efx_qword_t *) (rx_queue->rxd.addr)) + index); +} + +/* This creates an entry in the RX descriptor queue */ +static inline void +efx_build_rx_desc(struct efx_rx_queue *rx_queue, unsigned index) +{ + struct efx_rx_buffer *rx_buf; + efx_qword_t *rxd; + + rxd = efx_rx_desc(rx_queue, index); + rx_buf = efx_rx_buffer(rx_queue, index); + EFX_POPULATE_QWORD_3(*rxd, + FSF_AZ_RX_KER_BUF_SIZE, + rx_buf->len - + rx_queue->efx->type->rx_buffer_padding, + FSF_AZ_RX_KER_BUF_REGION, 0, + FSF_AZ_RX_KER_BUF_ADDR, rx_buf->dma_addr); +} + +/* This writes to the RX_DESC_WPTR register for the specified receive + * descriptor ring. + */ +void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue) +{ + efx_dword_t reg; + unsigned write_ptr; + + while (rx_queue->notified_count != rx_queue->added_count) { + efx_build_rx_desc(rx_queue, + rx_queue->notified_count & + EFX_RXQ_MASK); + ++rx_queue->notified_count; + } + + wmb(); + write_ptr = rx_queue->added_count & EFX_RXQ_MASK; + EFX_POPULATE_DWORD_1(reg, FRF_AZ_RX_DESC_WPTR_DWORD, write_ptr); + efx_writed_page(rx_queue->efx, ®, + FR_AZ_RX_DESC_UPD_DWORD_P0, rx_queue->queue); +} + +int efx_nic_probe_rx(struct efx_rx_queue *rx_queue) +{ + struct efx_nic *efx = rx_queue->efx; + BUILD_BUG_ON(EFX_RXQ_SIZE < 512 || EFX_RXQ_SIZE > 4096 || + EFX_RXQ_SIZE & EFX_RXQ_MASK); + return efx_alloc_special_buffer(efx, &rx_queue->rxd, + EFX_RXQ_SIZE * sizeof(efx_qword_t)); +} + +void efx_nic_init_rx(struct efx_rx_queue *rx_queue) +{ + efx_oword_t rx_desc_ptr; + struct efx_nic *efx = rx_queue->efx; + bool is_b0 = efx_nic_rev(efx) >= EFX_REV_FALCON_B0; + bool iscsi_digest_en = is_b0; + + EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n", + rx_queue->queue, rx_queue->rxd.index, + rx_queue->rxd.index + rx_queue->rxd.entries - 1); + + rx_queue->flushed = FLUSH_NONE; + + /* Pin RX descriptor ring */ + efx_init_special_buffer(efx, &rx_queue->rxd); + + /* Push RX descriptor ring to card */ + EFX_POPULATE_OWORD_10(rx_desc_ptr, + FRF_AZ_RX_ISCSI_DDIG_EN, iscsi_digest_en, + FRF_AZ_RX_ISCSI_HDIG_EN, iscsi_digest_en, + FRF_AZ_RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index, + FRF_AZ_RX_DESCQ_EVQ_ID, + rx_queue->channel->channel, + FRF_AZ_RX_DESCQ_OWNER_ID, 0, + FRF_AZ_RX_DESCQ_LABEL, rx_queue->queue, + FRF_AZ_RX_DESCQ_SIZE, + __ffs(rx_queue->rxd.entries), + FRF_AZ_RX_DESCQ_TYPE, 0 /* kernel queue */ , + /* For >=B0 this is scatter so disable */ + FRF_AZ_RX_DESCQ_JUMBO, !is_b0, + FRF_AZ_RX_DESCQ_EN, 1); + efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, + rx_queue->queue); +} + +static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue) +{ + struct efx_nic *efx = rx_queue->efx; + efx_oword_t rx_flush_descq; + + rx_queue->flushed = FLUSH_PENDING; + + /* Post a flush command */ + EFX_POPULATE_OWORD_2(rx_flush_descq, + FRF_AZ_RX_FLUSH_DESCQ_CMD, 1, + FRF_AZ_RX_FLUSH_DESCQ, rx_queue->queue); + efx_writeo(efx, &rx_flush_descq, FR_AZ_RX_FLUSH_DESCQ); +} + +void efx_nic_fini_rx(struct efx_rx_queue *rx_queue) +{ + efx_oword_t rx_desc_ptr; + struct efx_nic *efx = rx_queue->efx; + + /* The queue should already have been flushed */ + WARN_ON(rx_queue->flushed != FLUSH_DONE); + + /* Remove RX descriptor ring from card */ + EFX_ZERO_OWORD(rx_desc_ptr); + efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base, + rx_queue->queue); + + /* Unpin RX descriptor ring */ + efx_fini_special_buffer(efx, &rx_queue->rxd); +} + +/* Free buffers backing RX queue */ +void efx_nic_remove_rx(struct efx_rx_queue *rx_queue) +{ + efx_free_special_buffer(rx_queue->efx, &rx_queue->rxd); +} + +/************************************************************************** + * + * Event queue processing + * Event queues are processed by per-channel tasklets. + * + **************************************************************************/ + +/* Update a channel's event queue's read pointer (RPTR) register + * + * This writes the EVQ_RPTR_REG register for the specified channel's + * event queue. + * + * Note that EVQ_RPTR_REG contains the index of the "last read" event, + * whereas channel->eventq_read_ptr contains the index of the "next to + * read" event. + */ +void efx_nic_eventq_read_ack(struct efx_channel *channel) +{ + efx_dword_t reg; + struct efx_nic *efx = channel->efx; + + EFX_POPULATE_DWORD_1(reg, FRF_AZ_EVQ_RPTR, channel->eventq_read_ptr); + efx_writed_table(efx, ®, efx->type->evq_rptr_tbl_base, + channel->channel); +} + +/* Use HW to insert a SW defined event */ +void efx_generate_event(struct efx_channel *channel, efx_qword_t *event) +{ + efx_oword_t drv_ev_reg; + + BUILD_BUG_ON(FRF_AZ_DRV_EV_DATA_LBN != 0 || + FRF_AZ_DRV_EV_DATA_WIDTH != 64); + drv_ev_reg.u32[0] = event->u32[0]; + drv_ev_reg.u32[1] = event->u32[1]; + drv_ev_reg.u32[2] = 0; + drv_ev_reg.u32[3] = 0; + EFX_SET_OWORD_FIELD(drv_ev_reg, FRF_AZ_DRV_EV_QID, channel->channel); + efx_writeo(channel->efx, &drv_ev_reg, FR_AZ_DRV_EV); +} + +/* Handle a transmit completion event + * + * The NIC batches TX completion events; the message we receive is of + * the form "complete all TX events up to this index". + */ +static void +efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event) +{ + unsigned int tx_ev_desc_ptr; + unsigned int tx_ev_q_label; + struct efx_tx_queue *tx_queue; + struct efx_nic *efx = channel->efx; + + if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) { + /* Transmit completion */ + tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR); + tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); + tx_queue = &efx->tx_queue[tx_ev_q_label]; + channel->irq_mod_score += + (tx_ev_desc_ptr - tx_queue->read_count) & + EFX_TXQ_MASK; + efx_xmit_done(tx_queue, tx_ev_desc_ptr); + } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_WQ_FF_FULL)) { + /* Rewrite the FIFO write pointer */ + tx_ev_q_label = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_Q_LABEL); + tx_queue = &efx->tx_queue[tx_ev_q_label]; + + if (efx_dev_registered(efx)) + netif_tx_lock(efx->net_dev); + efx_notify_tx_desc(tx_queue); + if (efx_dev_registered(efx)) + netif_tx_unlock(efx->net_dev); + } else if (EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_PKT_ERR) && + EFX_WORKAROUND_10727(efx)) { + efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); + } else { + EFX_ERR(efx, "channel %d unexpected TX event " + EFX_QWORD_FMT"\n", channel->channel, + EFX_QWORD_VAL(*event)); + } +} + +/* Detect errors included in the rx_evt_pkt_ok bit. */ +static void efx_handle_rx_not_ok(struct efx_rx_queue *rx_queue, + const efx_qword_t *event, + bool *rx_ev_pkt_ok, + bool *discard) +{ + struct efx_nic *efx = rx_queue->efx; + bool rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err; + bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err; + bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc; + bool rx_ev_other_err, rx_ev_pause_frm; + bool rx_ev_hdr_type, rx_ev_mcast_pkt; + unsigned rx_ev_pkt_type; + + rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE); + rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT); + rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_TOBE_DISC); + rx_ev_pkt_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_TYPE); + rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event, + FSF_AZ_RX_EV_BUF_OWNER_ID_ERR); + rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event, + FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR); + rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event, + FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR); + rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_ETH_CRC_ERR); + rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_FRM_TRUNC); + rx_ev_drib_nib = ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ? + 0 : EFX_QWORD_FIELD(*event, FSF_AA_RX_EV_DRIB_NIB)); + rx_ev_pause_frm = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PAUSE_FRM_ERR); + + /* Every error apart from tobe_disc and pause_frm */ + rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err | + rx_ev_buf_owner_id_err | rx_ev_eth_crc_err | + rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err); + + /* Count errors that are not in MAC stats. Ignore expected + * checksum errors during self-test. */ + if (rx_ev_frm_trunc) + ++rx_queue->channel->n_rx_frm_trunc; + else if (rx_ev_tobe_disc) + ++rx_queue->channel->n_rx_tobe_disc; + else if (!efx->loopback_selftest) { + if (rx_ev_ip_hdr_chksum_err) + ++rx_queue->channel->n_rx_ip_hdr_chksum_err; + else if (rx_ev_tcp_udp_chksum_err) + ++rx_queue->channel->n_rx_tcp_udp_chksum_err; + } + + /* The frame must be discarded if any of these are true. */ + *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib | + rx_ev_tobe_disc | rx_ev_pause_frm); + + /* TOBE_DISC is expected on unicast mismatches; don't print out an + * error message. FRM_TRUNC indicates RXDP dropped the packet due + * to a FIFO overflow. + */ +#ifdef EFX_ENABLE_DEBUG + if (rx_ev_other_err) { + EFX_INFO_RL(efx, " RX queue %d unexpected RX event " + EFX_QWORD_FMT "%s%s%s%s%s%s%s%s\n", + rx_queue->queue, EFX_QWORD_VAL(*event), + rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "", + rx_ev_ip_hdr_chksum_err ? + " [IP_HDR_CHKSUM_ERR]" : "", + rx_ev_tcp_udp_chksum_err ? + " [TCP_UDP_CHKSUM_ERR]" : "", + rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "", + rx_ev_frm_trunc ? " [FRM_TRUNC]" : "", + rx_ev_drib_nib ? " [DRIB_NIB]" : "", + rx_ev_tobe_disc ? " [TOBE_DISC]" : "", + rx_ev_pause_frm ? " [PAUSE]" : ""); + } +#endif +} + +/* Handle receive events that are not in-order. */ +static void +efx_handle_rx_bad_index(struct efx_rx_queue *rx_queue, unsigned index) +{ + struct efx_nic *efx = rx_queue->efx; + unsigned expected, dropped; + + expected = rx_queue->removed_count & EFX_RXQ_MASK; + dropped = (index - expected) & EFX_RXQ_MASK; + EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n", + dropped, index, expected); + + efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ? + RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); +} + +/* Handle a packet received event + * + * The NIC gives a "discard" flag if it's a unicast packet with the + * wrong destination address + * Also "is multicast" and "matches multicast filter" flags can be used to + * discard non-matching multicast packets. + */ +static void +efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event) +{ + unsigned int rx_ev_desc_ptr, rx_ev_byte_cnt; + unsigned int rx_ev_hdr_type, rx_ev_mcast_pkt; + unsigned expected_ptr; + bool rx_ev_pkt_ok, discard = false, checksummed; + struct efx_rx_queue *rx_queue; + struct efx_nic *efx = channel->efx; + + /* Basic packet information */ + rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT); + rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_OK); + rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE); + WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_JUMBO_CONT)); + WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_SOP) != 1); + WARN_ON(EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_Q_LABEL) != + channel->channel); + + rx_queue = &efx->rx_queue[channel->channel]; + + rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_DESC_PTR); + expected_ptr = rx_queue->removed_count & EFX_RXQ_MASK; + if (unlikely(rx_ev_desc_ptr != expected_ptr)) + efx_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr); + + if (likely(rx_ev_pkt_ok)) { + /* If packet is marked as OK and packet type is TCP/IP or + * UDP/IP, then we can rely on the hardware checksum. + */ + checksummed = + likely(efx->rx_checksum_enabled) && + (rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP || + rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP); + } else { + efx_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, &discard); + checksummed = false; + } + + /* Detect multicast packets that didn't match the filter */ + rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_PKT); + if (rx_ev_mcast_pkt) { + unsigned int rx_ev_mcast_hash_match = + EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_HASH_MATCH); + + if (unlikely(!rx_ev_mcast_hash_match)) { + ++channel->n_rx_mcast_mismatch; + discard = true; + } + } + + channel->irq_mod_score += 2; + + /* Handle received packet */ + efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, + checksummed, discard); +} + +/* Global events are basically PHY events */ +static void +efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event) +{ + struct efx_nic *efx = channel->efx; + bool handled = false; + + if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) || + EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) || + EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) { + /* Ignored */ + handled = true; + } + + if ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) && + EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) { + efx->xmac_poll_required = true; + handled = true; + } + + if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ? + EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) : + EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) { + EFX_ERR(efx, "channel %d seen global RX_RESET " + "event. Resetting.\n", channel->channel); + + atomic_inc(&efx->rx_reset); + efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ? + RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE); + handled = true; + } + + if (!handled) + EFX_ERR(efx, "channel %d unknown global event " + EFX_QWORD_FMT "\n", channel->channel, + EFX_QWORD_VAL(*event)); +} + +static void +efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event) +{ + struct efx_nic *efx = channel->efx; + unsigned int ev_sub_code; + unsigned int ev_sub_data; + + ev_sub_code = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBCODE); + ev_sub_data = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA); + + switch (ev_sub_code) { + case FSE_AZ_TX_DESCQ_FLS_DONE_EV: + EFX_TRACE(efx, "channel %d TXQ %d flushed\n", + channel->channel, ev_sub_data); + break; + case FSE_AZ_RX_DESCQ_FLS_DONE_EV: + EFX_TRACE(efx, "channel %d RXQ %d flushed\n", + channel->channel, ev_sub_data); + break; + case FSE_AZ_EVQ_INIT_DONE_EV: + EFX_LOG(efx, "channel %d EVQ %d initialised\n", + channel->channel, ev_sub_data); + break; + case FSE_AZ_SRM_UPD_DONE_EV: + EFX_TRACE(efx, "channel %d SRAM update done\n", + channel->channel); + break; + case FSE_AZ_WAKE_UP_EV: + EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n", + channel->channel, ev_sub_data); + break; + case FSE_AZ_TIMER_EV: + EFX_TRACE(efx, "channel %d RX queue %d timer expired\n", + channel->channel, ev_sub_data); + break; + case FSE_AA_RX_RECOVER_EV: + EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. " + "Resetting.\n", channel->channel); + atomic_inc(&efx->rx_reset); + efx_schedule_reset(efx, + EFX_WORKAROUND_6555(efx) ? + RESET_TYPE_RX_RECOVERY : + RESET_TYPE_DISABLE); + break; + case FSE_BZ_RX_DSC_ERROR_EV: + EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error." + " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data); + efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH); + break; + case FSE_BZ_TX_DSC_ERROR_EV: + EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error." + " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data); + efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH); + break; + default: + EFX_TRACE(efx, "channel %d unknown driver event code %d " + "data %04x\n", channel->channel, ev_sub_code, + ev_sub_data); + break; + } +} + +int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota) +{ + unsigned int read_ptr; + efx_qword_t event, *p_event; + int ev_code; + int rx_packets = 0; + + read_ptr = channel->eventq_read_ptr; + + do { + p_event = efx_event(channel, read_ptr); + event = *p_event; + + if (!efx_event_present(&event)) + /* End of events */ + break; + + EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n", + channel->channel, EFX_QWORD_VAL(event)); + + /* Clear this event by marking it all ones */ + EFX_SET_QWORD(*p_event); + + ev_code = EFX_QWORD_FIELD(event, FSF_AZ_EV_CODE); + + switch (ev_code) { + case FSE_AZ_EV_CODE_RX_EV: + efx_handle_rx_event(channel, &event); + ++rx_packets; + break; + case FSE_AZ_EV_CODE_TX_EV: + efx_handle_tx_event(channel, &event); + break; + case FSE_AZ_EV_CODE_DRV_GEN_EV: + channel->eventq_magic = EFX_QWORD_FIELD( + event, FSF_AZ_DRV_GEN_EV_MAGIC); + EFX_LOG(channel->efx, "channel %d received generated " + "event "EFX_QWORD_FMT"\n", channel->channel, + EFX_QWORD_VAL(event)); + break; + case FSE_AZ_EV_CODE_GLOBAL_EV: + efx_handle_global_event(channel, &event); + break; + case FSE_AZ_EV_CODE_DRIVER_EV: + efx_handle_driver_event(channel, &event); + break; + case FSE_CZ_EV_CODE_MCDI_EV: + efx_mcdi_process_event(channel, &event); + break; + default: + EFX_ERR(channel->efx, "channel %d unknown event type %d" + " (data " EFX_QWORD_FMT ")\n", channel->channel, + ev_code, EFX_QWORD_VAL(event)); + } + + /* Increment read pointer */ + read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; + + } while (rx_packets < rx_quota); + + channel->eventq_read_ptr = read_ptr; + return rx_packets; +} + + +/* Allocate buffer table entries for event queue */ +int efx_nic_probe_eventq(struct efx_channel *channel) +{ + struct efx_nic *efx = channel->efx; + BUILD_BUG_ON(EFX_EVQ_SIZE < 512 || EFX_EVQ_SIZE > 32768 || + EFX_EVQ_SIZE & EFX_EVQ_MASK); + return efx_alloc_special_buffer(efx, &channel->eventq, + EFX_EVQ_SIZE * sizeof(efx_qword_t)); +} + +void efx_nic_init_eventq(struct efx_channel *channel) +{ + efx_oword_t reg; + struct efx_nic *efx = channel->efx; + + EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", + channel->channel, channel->eventq.index, + channel->eventq.index + channel->eventq.entries - 1); + + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) { + EFX_POPULATE_OWORD_3(reg, + FRF_CZ_TIMER_Q_EN, 1, + FRF_CZ_HOST_NOTIFY_MODE, 0, + FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS); + efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); + } + + /* Pin event queue buffer */ + efx_init_special_buffer(efx, &channel->eventq); + + /* Fill event queue with all ones (i.e. empty events) */ + memset(channel->eventq.addr, 0xff, channel->eventq.len); + + /* Push event queue to card */ + EFX_POPULATE_OWORD_3(reg, + FRF_AZ_EVQ_EN, 1, + FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries), + FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index); + efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, + channel->channel); + + efx->type->push_irq_moderation(channel); +} + +void efx_nic_fini_eventq(struct efx_channel *channel) +{ + efx_oword_t reg; + struct efx_nic *efx = channel->efx; + + /* Remove event queue from card */ + EFX_ZERO_OWORD(reg); + efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, + channel->channel); + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) + efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); + + /* Unpin event queue */ + efx_fini_special_buffer(efx, &channel->eventq); +} + +/* Free buffers backing event queue */ +void efx_nic_remove_eventq(struct efx_channel *channel) +{ + efx_free_special_buffer(channel->efx, &channel->eventq); +} + + +/* Generates a test event on the event queue. A subsequent call to + * process_eventq() should pick up the event and place the value of + * "magic" into channel->eventq_magic; + */ +void efx_nic_generate_test_event(struct efx_channel *channel, unsigned int magic) +{ + efx_qword_t test_event; + + EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE, + FSE_AZ_EV_CODE_DRV_GEN_EV, + FSF_AZ_DRV_GEN_EV_MAGIC, magic); + efx_generate_event(channel, &test_event); +} + +/************************************************************************** + * + * Flush handling + * + **************************************************************************/ + + +static void efx_poll_flush_events(struct efx_nic *efx) +{ + struct efx_channel *channel = &efx->channel[0]; + struct efx_tx_queue *tx_queue; + struct efx_rx_queue *rx_queue; + unsigned int read_ptr = channel->eventq_read_ptr; + unsigned int end_ptr = (read_ptr - 1) & EFX_EVQ_MASK; + + do { + efx_qword_t *event = efx_event(channel, read_ptr); + int ev_code, ev_sub_code, ev_queue; + bool ev_failed; + + if (!efx_event_present(event)) + break; + + ev_code = EFX_QWORD_FIELD(*event, FSF_AZ_EV_CODE); + ev_sub_code = EFX_QWORD_FIELD(*event, + FSF_AZ_DRIVER_EV_SUBCODE); + if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV && + ev_sub_code == FSE_AZ_TX_DESCQ_FLS_DONE_EV) { + ev_queue = EFX_QWORD_FIELD(*event, + FSF_AZ_DRIVER_EV_SUBDATA); + if (ev_queue < EFX_TX_QUEUE_COUNT) { + tx_queue = efx->tx_queue + ev_queue; + tx_queue->flushed = FLUSH_DONE; + } + } else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV && + ev_sub_code == FSE_AZ_RX_DESCQ_FLS_DONE_EV) { + ev_queue = EFX_QWORD_FIELD( + *event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID); + ev_failed = EFX_QWORD_FIELD( + *event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL); + if (ev_queue < efx->n_rx_queues) { + rx_queue = efx->rx_queue + ev_queue; + rx_queue->flushed = + ev_failed ? FLUSH_FAILED : FLUSH_DONE; + } + } + + /* We're about to destroy the queue anyway, so + * it's ok to throw away every non-flush event */ + EFX_SET_QWORD(*event); + + read_ptr = (read_ptr + 1) & EFX_EVQ_MASK; + } while (read_ptr != end_ptr); + + channel->eventq_read_ptr = read_ptr; +} + +/* Handle tx and rx flushes at the same time, since they run in + * parallel in the hardware and there's no reason for us to + * serialise them */ +int efx_nic_flush_queues(struct efx_nic *efx) +{ + struct efx_rx_queue *rx_queue; + struct efx_tx_queue *tx_queue; + int i, tx_pending, rx_pending; + + /* If necessary prepare the hardware for flushing */ + efx->type->prepare_flush(efx); + + /* Flush all tx queues in parallel */ + efx_for_each_tx_queue(tx_queue, efx) + efx_flush_tx_queue(tx_queue); + + /* The hardware supports four concurrent rx flushes, each of which may + * need to be retried if there is an outstanding descriptor fetch */ + for (i = 0; i < EFX_FLUSH_POLL_COUNT; ++i) { + rx_pending = tx_pending = 0; + efx_for_each_rx_queue(rx_queue, efx) { + if (rx_queue->flushed == FLUSH_PENDING) + ++rx_pending; + } + efx_for_each_rx_queue(rx_queue, efx) { + if (rx_pending == EFX_RX_FLUSH_COUNT) + break; + if (rx_queue->flushed == FLUSH_FAILED || + rx_queue->flushed == FLUSH_NONE) { + efx_flush_rx_queue(rx_queue); + ++rx_pending; + } + } + efx_for_each_tx_queue(tx_queue, efx) { + if (tx_queue->flushed != FLUSH_DONE) + ++tx_pending; + } + + if (rx_pending == 0 && tx_pending == 0) + return 0; + + msleep(EFX_FLUSH_INTERVAL); + efx_poll_flush_events(efx); + } + + /* Mark the queues as all flushed. We're going to return failure + * leading to a reset, or fake up success anyway */ + efx_for_each_tx_queue(tx_queue, efx) { + if (tx_queue->flushed != FLUSH_DONE) + EFX_ERR(efx, "tx queue %d flush command timed out\n", + tx_queue->queue); + tx_queue->flushed = FLUSH_DONE; + } + efx_for_each_rx_queue(rx_queue, efx) { + if (rx_queue->flushed != FLUSH_DONE) + EFX_ERR(efx, "rx queue %d flush command timed out\n", + rx_queue->queue); + rx_queue->flushed = FLUSH_DONE; + } + + if (EFX_WORKAROUND_7803(efx)) + return 0; + + return -ETIMEDOUT; +} + +/************************************************************************** + * + * Hardware interrupts + * The hardware interrupt handler does very little work; all the event + * queue processing is carried out by per-channel tasklets. + * + **************************************************************************/ + +/* Enable/disable/generate interrupts */ +static inline void efx_nic_interrupts(struct efx_nic *efx, + bool enabled, bool force) +{ + efx_oword_t int_en_reg_ker; + unsigned int level = 0; + + if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx)) + /* Set the level always even if we're generating a test + * interrupt, because our legacy interrupt handler is safe */ + level = 0x1f; + + EFX_POPULATE_OWORD_3(int_en_reg_ker, + FRF_AZ_KER_INT_LEVE_SEL, level, + FRF_AZ_KER_INT_KER, force, + FRF_AZ_DRV_INT_EN_KER, enabled); + efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); +} + +void efx_nic_enable_interrupts(struct efx_nic *efx) +{ + struct efx_channel *channel; + + EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr)); + wmb(); /* Ensure interrupt vector is clear before interrupts enabled */ + + /* Enable interrupts */ + efx_nic_interrupts(efx, true, false); + + /* Force processing of all the channels to get the EVQ RPTRs up to + date */ + efx_for_each_channel(channel, efx) + efx_schedule_channel(channel); +} + +void efx_nic_disable_interrupts(struct efx_nic *efx) +{ + /* Disable interrupts */ + efx_nic_interrupts(efx, false, false); +} + +/* Generate a test interrupt + * Interrupt must already have been enabled, otherwise nasty things + * may happen. + */ +void efx_nic_generate_interrupt(struct efx_nic *efx) +{ + efx_nic_interrupts(efx, true, true); +} + +/* Process a fatal interrupt + * Disable bus mastering ASAP and schedule a reset + */ +irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx) +{ + struct falcon_nic_data *nic_data = efx->nic_data; + efx_oword_t *int_ker = efx->irq_status.addr; + efx_oword_t fatal_intr; + int error, mem_perr; + + efx_reado(efx, &fatal_intr, FR_AZ_FATAL_INTR_KER); + error = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_FATAL_INTR); + + EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status " + EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker), + EFX_OWORD_VAL(fatal_intr), + error ? "disabling bus mastering" : "no recognised error"); + if (error == 0) + goto out; + + /* If this is a memory parity error dump which blocks are offending */ + mem_perr = EFX_OWORD_FIELD(fatal_intr, FRF_AZ_MEM_PERR_INT_KER); + if (mem_perr) { + efx_oword_t reg; + efx_reado(efx, ®, FR_AZ_MEM_STAT); + EFX_ERR(efx, "SYSTEM ERROR: memory parity error " + EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg)); + } + + /* Disable both devices */ + pci_clear_master(efx->pci_dev); + if (efx_nic_is_dual_func(efx)) + pci_clear_master(nic_data->pci_dev2); + efx_nic_disable_interrupts(efx); + + /* Count errors and reset or disable the NIC accordingly */ + if (efx->int_error_count == 0 || + time_after(jiffies, efx->int_error_expire)) { + efx->int_error_count = 0; + efx->int_error_expire = + jiffies + EFX_INT_ERROR_EXPIRE * HZ; + } + if (++efx->int_error_count < EFX_MAX_INT_ERRORS) { + EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n"); + efx_schedule_reset(efx, RESET_TYPE_INT_ERROR); + } else { + EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen." + "NIC will be disabled\n"); + efx_schedule_reset(efx, RESET_TYPE_DISABLE); + } +out: + return IRQ_HANDLED; +} + +/* Handle a legacy interrupt + * Acknowledges the interrupt and schedule event queue processing. + */ +static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) +{ + struct efx_nic *efx = dev_id; + efx_oword_t *int_ker = efx->irq_status.addr; + irqreturn_t result = IRQ_NONE; + struct efx_channel *channel; + efx_dword_t reg; + u32 queues; + int syserr; + + /* Read the ISR which also ACKs the interrupts */ + efx_readd(efx, ®, FR_BZ_INT_ISR0); + queues = EFX_EXTRACT_DWORD(reg, 0, 31); + + /* Check to see if we have a serious error condition */ + syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); + if (unlikely(syserr)) + return efx_nic_fatal_interrupt(efx); + + if (queues != 0) { + if (EFX_WORKAROUND_15783(efx)) + efx->irq_zero_count = 0; + + /* Schedule processing of any interrupting queues */ + efx_for_each_channel(channel, efx) { + if (queues & 1) + efx_schedule_channel(channel); + queues >>= 1; + } + result = IRQ_HANDLED; + + } else if (EFX_WORKAROUND_15783(efx) && + efx->irq_zero_count++ == 0) { + efx_qword_t *event; + + /* Ensure we rearm all event queues */ + efx_for_each_channel(channel, efx) { + event = efx_event(channel, channel->eventq_read_ptr); + if (efx_event_present(event)) + efx_schedule_channel(channel); + } + + result = IRQ_HANDLED; + } + + if (result == IRQ_HANDLED) { + efx->last_irq_cpu = raw_smp_processor_id(); + EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n", + irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg)); + } + + return result; +} + +/* Handle an MSI interrupt + * + * Handle an MSI hardware interrupt. This routine schedules event + * queue processing. No interrupt acknowledgement cycle is necessary. + * Also, we never need to check that the interrupt is for us, since + * MSI interrupts cannot be shared. + */ +static irqreturn_t efx_msi_interrupt(int irq, void *dev_id) +{ + struct efx_channel *channel = dev_id; + struct efx_nic *efx = channel->efx; + efx_oword_t *int_ker = efx->irq_status.addr; + int syserr; + + efx->last_irq_cpu = raw_smp_processor_id(); + EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n", + irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker)); + + /* Check to see if we have a serious error condition */ + syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT); + if (unlikely(syserr)) + return efx_nic_fatal_interrupt(efx); + + /* Schedule processing of the channel */ + efx_schedule_channel(channel); + + return IRQ_HANDLED; +} + + +/* Setup RSS indirection table. + * This maps from the hash value of the packet to RXQ + */ +static void efx_setup_rss_indir_table(struct efx_nic *efx) +{ + int i = 0; + unsigned long offset; + efx_dword_t dword; + + if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) + return; + + for (offset = FR_BZ_RX_INDIRECTION_TBL; + offset < FR_BZ_RX_INDIRECTION_TBL + 0x800; + offset += 0x10) { + EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE, + i % efx->n_rx_queues); + efx_writed(efx, &dword, offset); + i++; + } +} + +/* Hook interrupt handler(s) + * Try MSI and then legacy interrupts. + */ +int efx_nic_init_interrupt(struct efx_nic *efx) +{ + struct efx_channel *channel; + int rc; + + if (!EFX_INT_MODE_USE_MSI(efx)) { + irq_handler_t handler; + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) + handler = efx_legacy_interrupt; + else + handler = falcon_legacy_interrupt_a1; + + rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED, + efx->name, efx); + if (rc) { + EFX_ERR(efx, "failed to hook legacy IRQ %d\n", + efx->pci_dev->irq); + goto fail1; + } + return 0; + } + + /* Hook MSI or MSI-X interrupt */ + efx_for_each_channel(channel, efx) { + rc = request_irq(channel->irq, efx_msi_interrupt, + IRQF_PROBE_SHARED, /* Not shared */ + channel->name, channel); + if (rc) { + EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq); + goto fail2; + } + } + + return 0; + + fail2: + efx_for_each_channel(channel, efx) + free_irq(channel->irq, channel); + fail1: + return rc; +} + +void efx_nic_fini_interrupt(struct efx_nic *efx) +{ + struct efx_channel *channel; + efx_oword_t reg; + + /* Disable MSI/MSI-X interrupts */ + efx_for_each_channel(channel, efx) { + if (channel->irq) + free_irq(channel->irq, channel); + } + + /* ACK legacy interrupt */ + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) + efx_reado(efx, ®, FR_BZ_INT_ISR0); + else + falcon_irq_ack_a1(efx); + + /* Disable legacy interrupt */ + if (efx->legacy_irq) + free_irq(efx->legacy_irq, efx); +} + +u32 efx_nic_fpga_ver(struct efx_nic *efx) +{ + efx_oword_t altera_build; + efx_reado(efx, &altera_build, FR_AZ_ALTERA_BUILD); + return EFX_OWORD_FIELD(altera_build, FRF_AZ_ALTERA_BUILD_VER); +} + +void efx_nic_init_common(struct efx_nic *efx) +{ + efx_oword_t temp; + + /* Set positions of descriptor caches in SRAM. */ + EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR, + efx->type->tx_dc_base / 8); + efx_writeo(efx, &temp, FR_AZ_SRM_TX_DC_CFG); + EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR, + efx->type->rx_dc_base / 8); + efx_writeo(efx, &temp, FR_AZ_SRM_RX_DC_CFG); + + /* Set TX descriptor cache size. */ + BUILD_BUG_ON(TX_DC_ENTRIES != (8 << TX_DC_ENTRIES_ORDER)); + EFX_POPULATE_OWORD_1(temp, FRF_AZ_TX_DC_SIZE, TX_DC_ENTRIES_ORDER); + efx_writeo(efx, &temp, FR_AZ_TX_DC_CFG); + + /* Set RX descriptor cache size. Set low watermark to size-8, as + * this allows most efficient prefetching. + */ + BUILD_BUG_ON(RX_DC_ENTRIES != (8 << RX_DC_ENTRIES_ORDER)); + EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_SIZE, RX_DC_ENTRIES_ORDER); + efx_writeo(efx, &temp, FR_AZ_RX_DC_CFG); + EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_PF_LWM, RX_DC_ENTRIES - 8); + efx_writeo(efx, &temp, FR_AZ_RX_DC_PF_WM); + + /* Program INT_KER address */ + EFX_POPULATE_OWORD_2(temp, + FRF_AZ_NORM_INT_VEC_DIS_KER, + EFX_INT_MODE_USE_MSI(efx), + FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr); + efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER); + + /* Enable all the genuinely fatal interrupts. (They are still + * masked by the overall interrupt mask, controlled by + * falcon_interrupts()). + * + * Note: All other fatal interrupts are enabled + */ + EFX_POPULATE_OWORD_3(temp, + FRF_AZ_ILL_ADR_INT_KER_EN, 1, + FRF_AZ_RBUF_OWN_INT_KER_EN, 1, + FRF_AZ_TBUF_OWN_INT_KER_EN, 1); + EFX_INVERT_OWORD(temp); + efx_writeo(efx, &temp, FR_AZ_FATAL_INTR_KER); + + efx_setup_rss_indir_table(efx); + + /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be + * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q. + */ + efx_reado(efx, &temp, FR_AZ_TX_RESERVED); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER, 0xfe); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_RX_SPACER_EN, 1); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_ONE_PKT_PER_Q, 1); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PUSH_EN, 0); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_DIS_NON_IP_EV, 1); + /* Enable SW_EV to inherit in char driver - assume harmless here */ + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_SOFT_EVT_EN, 1); + /* Prefetch threshold 2 => fetch when descriptor cache half empty */ + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2); + /* Squash TX of packets of 16 bytes or less */ + if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) + EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); + efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); +} diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h new file mode 100644 index 00000000000..9351c0331a4 --- /dev/null +++ b/drivers/net/sfc/nic.h @@ -0,0 +1,261 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#ifndef EFX_NIC_H +#define EFX_NIC_H + +#include <linux/i2c-algo-bit.h> +#include "net_driver.h" +#include "efx.h" +#include "mcdi.h" + +/* + * Falcon hardware control + */ + +enum { + EFX_REV_FALCON_A0 = 0, + EFX_REV_FALCON_A1 = 1, + EFX_REV_FALCON_B0 = 2, + EFX_REV_SIENA_A0 = 3, +}; + +static inline int efx_nic_rev(struct efx_nic *efx) +{ + return efx->type->revision; +} + +extern u32 efx_nic_fpga_ver(struct efx_nic *efx); + +static inline bool efx_nic_has_mc(struct efx_nic *efx) +{ + return efx_nic_rev(efx) >= EFX_REV_SIENA_A0; +} +/* NIC has two interlinked PCI functions for the same port. */ +static inline bool efx_nic_is_dual_func(struct efx_nic *efx) +{ + return efx_nic_rev(efx) < EFX_REV_FALCON_B0; +} + +enum { + PHY_TYPE_NONE = 0, + PHY_TYPE_TXC43128 = 1, + PHY_TYPE_88E1111 = 2, + PHY_TYPE_SFX7101 = 3, + PHY_TYPE_QT2022C2 = 4, + PHY_TYPE_PM8358 = 6, + PHY_TYPE_SFT9001A = 8, + PHY_TYPE_QT2025C = 9, + PHY_TYPE_SFT9001B = 10, +}; + +#define FALCON_XMAC_LOOPBACKS \ + ((1 << LOOPBACK_XGMII) | \ + (1 << LOOPBACK_XGXS) | \ + (1 << LOOPBACK_XAUI)) + +#define FALCON_GMAC_LOOPBACKS \ + (1 << LOOPBACK_GMAC) + +/** + * struct falcon_board_type - board operations and type information + * @id: Board type id, as found in NVRAM + * @ref_model: Model number of Solarflare reference design + * @gen_type: Generic board type description + * @init: Allocate resources and initialise peripheral hardware + * @init_phy: Do board-specific PHY initialisation + * @fini: Shut down hardware and free resources + * @set_id_led: Set state of identifying LED or revert to automatic function + * @monitor: Board-specific health check function + */ +struct falcon_board_type { + u8 id; + const char *ref_model; + const char *gen_type; + int (*init) (struct efx_nic *nic); + void (*init_phy) (struct efx_nic *efx); + void (*fini) (struct efx_nic *nic); + void (*set_id_led) (struct efx_nic *efx, enum efx_led_mode mode); + int (*monitor) (struct efx_nic *nic); +}; + +/** + * struct falcon_board - board information + * @type: Type of board + * @major: Major rev. ('A', 'B' ...) + * @minor: Minor rev. (0, 1, ...) + * @i2c_adap: I2C adapter for on-board peripherals + * @i2c_data: Data for bit-banging algorithm + * @hwmon_client: I2C client for hardware monitor + * @ioexp_client: I2C client for power/port control + */ +struct falcon_board { + const struct falcon_board_type *type; + int major; + int minor; + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_data; + struct i2c_client *hwmon_client, *ioexp_client; +}; + +/** + * struct falcon_nic_data - Falcon NIC state + * @pci_dev2: Secondary function of Falcon A + * @board: Board state and functions + * @stats_disable_count: Nest count for disabling statistics fetches + * @stats_pending: Is there a pending DMA of MAC statistics. + * @stats_timer: A timer for regularly fetching MAC statistics. + * @stats_dma_done: Pointer to the flag which indicates DMA completion. + */ +struct falcon_nic_data { + struct pci_dev *pci_dev2; + struct falcon_board board; + unsigned int stats_disable_count; + bool stats_pending; + struct timer_list stats_timer; + u32 *stats_dma_done; +}; + +static inline struct falcon_board *falcon_board(struct efx_nic *efx) +{ + struct falcon_nic_data *data = efx->nic_data; + return &data->board; +} + +/** + * struct siena_nic_data - Siena NIC state + * @fw_version: Management controller firmware version + * @fw_build: Firmware build number + * @mcdi: Management-Controller-to-Driver Interface + * @wol_filter_id: Wake-on-LAN packet filter id + */ +struct siena_nic_data { + u64 fw_version; + u32 fw_build; + struct efx_mcdi_iface mcdi; + int wol_filter_id; +}; + +extern void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len); + +extern struct efx_nic_type falcon_a1_nic_type; +extern struct efx_nic_type falcon_b0_nic_type; +extern struct efx_nic_type siena_a0_nic_type; + +/************************************************************************** + * + * Externs + * + ************************************************************************** + */ + +extern void falcon_probe_board(struct efx_nic *efx, u16 revision_info); + +/* TX data path */ +extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_init_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_fini_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_remove_tx(struct efx_tx_queue *tx_queue); +extern void efx_nic_push_buffers(struct efx_tx_queue *tx_queue); + +/* RX data path */ +extern int efx_nic_probe_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_init_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_fini_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_remove_rx(struct efx_rx_queue *rx_queue); +extern void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue); + +/* Event data path */ +extern int efx_nic_probe_eventq(struct efx_channel *channel); +extern void efx_nic_init_eventq(struct efx_channel *channel); +extern void efx_nic_fini_eventq(struct efx_channel *channel); +extern void efx_nic_remove_eventq(struct efx_channel *channel); +extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota); +extern void efx_nic_eventq_read_ack(struct efx_channel *channel); + +/* MAC/PHY */ +extern void falcon_drain_tx_fifo(struct efx_nic *efx); +extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx); +extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh; + +/* Interrupts and test events */ +extern int efx_nic_init_interrupt(struct efx_nic *efx); +extern void efx_nic_enable_interrupts(struct efx_nic *efx); +extern void efx_nic_generate_test_event(struct efx_channel *channel, + unsigned int magic); +extern void efx_nic_generate_interrupt(struct efx_nic *efx); +extern void efx_nic_disable_interrupts(struct efx_nic *efx); +extern void efx_nic_fini_interrupt(struct efx_nic *efx); +extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx); +extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id); +extern void falcon_irq_ack_a1(struct efx_nic *efx); + +#define EFX_IRQ_MOD_RESOLUTION 5 + +/* Global Resources */ +extern int efx_nic_flush_queues(struct efx_nic *efx); +extern void falcon_start_nic_stats(struct efx_nic *efx); +extern void falcon_stop_nic_stats(struct efx_nic *efx); +extern int falcon_reset_xaui(struct efx_nic *efx); +extern void efx_nic_init_common(struct efx_nic *efx); + +int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, + unsigned int len); +void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer); + +/* Tests */ +struct efx_nic_register_test { + unsigned address; + efx_oword_t mask; +}; +extern int efx_nic_test_registers(struct efx_nic *efx, + const struct efx_nic_register_test *regs, + size_t n_regs); + +/************************************************************************** + * + * Falcon MAC stats + * + ************************************************************************** + */ + +#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset) +#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH) + +/* Retrieve statistic from statistics block */ +#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \ + if (FALCON_STAT_WIDTH(falcon_stat) == 16) \ + (efx)->mac_stats.efx_stat += le16_to_cpu( \ + *((__force __le16 *) \ + (efx->stats_buffer.addr + \ + FALCON_STAT_OFFSET(falcon_stat)))); \ + else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \ + (efx)->mac_stats.efx_stat += le32_to_cpu( \ + *((__force __le32 *) \ + (efx->stats_buffer.addr + \ + FALCON_STAT_OFFSET(falcon_stat)))); \ + else \ + (efx)->mac_stats.efx_stat += le64_to_cpu( \ + *((__force __le64 *) \ + (efx->stats_buffer.addr + \ + FALCON_STAT_OFFSET(falcon_stat)))); \ + } while (0) + +#define FALCON_MAC_STATS_SIZE 0x100 + +#define MAC_DATA_LBN 0 +#define MAC_DATA_WIDTH 32 + +extern void efx_nic_generate_event(struct efx_channel *channel, + efx_qword_t *event); + +extern void falcon_poll_xmac(struct efx_nic *efx); + +#endif /* EFX_NIC_H */ diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index 2ad1cec2c72..5bc26137257 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2008 Solarflare Communications Inc. + * Copyright 2007-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -41,4 +41,21 @@ extern struct efx_phy_operations falcon_qt202x_phy_ops; extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state); +/**************************************************************************** + * Siena managed PHYs + */ +extern struct efx_phy_operations efx_mcdi_phy_ops; + +extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus, + unsigned int prtad, unsigned int devad, + u16 addr, u16 *value_out, u32 *status_out); +extern int efx_mcdi_mdio_write(struct efx_nic *efx, unsigned int bus, + unsigned int prtad, unsigned int devad, + u16 addr, u16 value, u32 *status_out); +extern void efx_mcdi_phy_decode_link(struct efx_nic *efx, + struct efx_link_state *link_state, + u32 speed, u32 flags, u32 fcntl); +extern int efx_mcdi_phy_reconfigure(struct efx_nic *efx); +extern void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa); + #endif diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c index 8208ac0ffad..3800fc791b2 100644 --- a/drivers/net/sfc/qt202x_phy.c +++ b/drivers/net/sfc/qt202x_phy.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -15,7 +15,7 @@ #include "efx.h" #include "mdio_10g.h" #include "phy.h" -#include "falcon.h" +#include "nic.h" #define QT202X_REQUIRED_DEVS (MDIO_DEVS_PCS | \ MDIO_DEVS_PMAPMD | \ @@ -23,7 +23,7 @@ #define QT202X_LOOPBACKS ((1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PMAPMD) | \ - (1 << LOOPBACK_NETWORK)) + (1 << LOOPBACK_PHYXS_WS)) /****************************************************************************/ /* Quake-specific MDIO registers */ @@ -126,7 +126,7 @@ static int qt202x_reset_phy(struct efx_nic *efx) if (rc < 0) goto fail; - falcon_board(efx)->init_phy(efx); + falcon_board(efx)->type->init_phy(efx); return rc; @@ -135,42 +135,38 @@ static int qt202x_reset_phy(struct efx_nic *efx) return rc; } +static int qt202x_phy_probe(struct efx_nic *efx) +{ + efx->mdio.mmds = QT202X_REQUIRED_DEVS; + efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + efx->loopback_modes = QT202X_LOOPBACKS | FALCON_XMAC_LOOPBACKS; + return 0; +} + static int qt202x_phy_init(struct efx_nic *efx) { struct qt202x_phy_data *phy_data; - u32 devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); + u32 devid; int rc; + rc = qt202x_reset_phy(efx); + if (rc) { + EFX_ERR(efx, "PHY init failed\n"); + return rc; + } + phy_data = kzalloc(sizeof(struct qt202x_phy_data), GFP_KERNEL); if (!phy_data) return -ENOMEM; efx->phy_data = phy_data; + devid = efx_mdio_read_id(efx, MDIO_MMD_PHYXS); EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n", devid, efx_mdio_id_oui(devid), efx_mdio_id_model(devid), efx_mdio_id_rev(devid)); phy_data->phy_mode = efx->phy_mode; - - rc = qt202x_reset_phy(efx); - - EFX_INFO(efx, "PHY init %s.\n", - rc ? "failed" : "successful"); - if (rc < 0) - goto fail; - return 0; - - fail: - kfree(efx->phy_data); - efx->phy_data = NULL; - return rc; -} - -static void qt202x_phy_clear_interrupt(struct efx_nic *efx) -{ - /* Read to clear link status alarm */ - efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT); } static int qt202x_link_ok(struct efx_nic *efx) @@ -178,18 +174,21 @@ static int qt202x_link_ok(struct efx_nic *efx) return efx_mdio_links_ok(efx, QT202X_REQUIRED_DEVS); } -static void qt202x_phy_poll(struct efx_nic *efx) +static bool qt202x_phy_poll(struct efx_nic *efx) { - int link_up = qt202x_link_ok(efx); - /* Simulate a PHY event if link state has changed */ - if (link_up != efx->link_state.up) - falcon_sim_phy_event(efx); + bool was_up = efx->link_state.up; + + efx->link_state.up = qt202x_link_ok(efx); + efx->link_state.speed = 10000; + efx->link_state.fd = true; + efx->link_state.fc = efx->wanted_fc; + + return efx->link_state.up != was_up; } -static void qt202x_phy_reconfigure(struct efx_nic *efx) +static int qt202x_phy_reconfigure(struct efx_nic *efx) { struct qt202x_phy_data *phy_data = efx->phy_data; - struct efx_link_state *link_state = &efx->link_state; if (efx->phy_type == PHY_TYPE_QT2025C) { /* There are several different register bits which can @@ -216,10 +215,8 @@ static void qt202x_phy_reconfigure(struct efx_nic *efx) efx_mdio_phy_reconfigure(efx); phy_data->phy_mode = efx->phy_mode; - link_state->up = qt202x_link_ok(efx); - link_state->speed = 10000; - link_state->fd = true; - link_state->fc = efx->wanted_fc; + + return 0; } static void qt202x_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) @@ -235,14 +232,11 @@ static void qt202x_phy_fini(struct efx_nic *efx) } struct efx_phy_operations falcon_qt202x_phy_ops = { - .macs = EFX_XMAC, + .probe = qt202x_phy_probe, .init = qt202x_phy_init, .reconfigure = qt202x_phy_reconfigure, .poll = qt202x_phy_poll, .fini = qt202x_phy_fini, - .clear_interrupt = qt202x_phy_clear_interrupt, .get_settings = qt202x_phy_get_settings, .set_settings = efx_mdio_set_settings, - .mmds = QT202X_REQUIRED_DEVS, - .loopbacks = QT202X_LOOPBACKS, }; diff --git a/drivers/net/sfc/regs.h b/drivers/net/sfc/regs.h index f336d83d5fa..89d606fe924 100644 --- a/drivers/net/sfc/regs.h +++ b/drivers/net/sfc/regs.h @@ -3106,18 +3106,6 @@ #define FALCON_STATS_NOT_DONE 0x00000000 #define FALCON_STATS_DONE 0xffffffff -/* Interrupt status register bits */ -#define FATAL_INT_LBN 64 -#define FATAL_INT_WIDTH 1 -#define INT_EVQS_LBN 40 -#define INT_EVQS_WIDTH 4 -#define INT_FLAG_LBN 32 -#define INT_FLAG_WIDTH 1 -#define EVQ_FIFO_HF_LBN 1 -#define EVQ_FIFO_HF_WIDTH 1 -#define EVQ_FIFO_AF_LBN 0 -#define EVQ_FIFO_AF_WIDTH 1 - /************************************************************************** * * Falcon non-volatile configuration diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index accf055ff89..a97c923b560 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2008 Solarflare Communications Inc. + * Copyright 2005-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -17,7 +17,7 @@ #include <net/checksum.h> #include "net_driver.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "selftest.h" #include "workarounds.h" @@ -341,7 +341,7 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, out: /* Send write pointer to card. */ - falcon_notify_rx_desc(rx_queue); + efx_nic_notify_rx_desc(rx_queue); /* If the fast fill is running inside from the refill tasklet, then * for SMP systems it may be running on a different CPU to @@ -640,7 +640,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue) if (!rx_queue->buffer) return -ENOMEM; - rc = falcon_probe_rx(rx_queue); + rc = efx_nic_probe_rx(rx_queue); if (rc) { kfree(rx_queue->buffer); rx_queue->buffer = NULL; @@ -671,7 +671,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue) rx_queue->fast_fill_limit = limit; /* Set up RX descriptor ring */ - falcon_init_rx(rx_queue); + efx_nic_init_rx(rx_queue); } void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) @@ -681,7 +681,7 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue) EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue); - falcon_fini_rx(rx_queue); + efx_nic_fini_rx(rx_queue); /* Release RX buffers NB start at index 0 not current HW ptr */ if (rx_queue->buffer) { @@ -706,7 +706,7 @@ void efx_remove_rx_queue(struct efx_rx_queue *rx_queue) { EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue); - falcon_remove_rx(rx_queue); + efx_nic_remove_rx(rx_queue); kfree(rx_queue->buffer); rx_queue->buffer = NULL; diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 63ff295334e..14949bb303a 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -21,7 +21,7 @@ #include <asm/io.h> #include "net_driver.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "selftest.h" #include "workarounds.h" #include "spi.h" @@ -55,6 +55,7 @@ static const char *payload_msg = * @flush: Drop all packets in efx_loopback_rx_packet * @packet_count: Number of packets being used in this test * @skbs: An array of skbs transmitted + * @offload_csum: Checksums are being offloaded * @rx_good: RX good packet count * @rx_bad: RX bad packet count * @payload: Payload used in tests @@ -63,10 +64,7 @@ struct efx_loopback_state { bool flush; int packet_count; struct sk_buff **skbs; - - /* Checksums are being offloaded */ bool offload_csum; - atomic_t rx_good; atomic_t rx_bad; struct efx_loopback_payload payload; @@ -102,7 +100,7 @@ static int efx_test_mdio(struct efx_nic *efx, struct efx_self_tests *tests) } if (EFX_IS10G(efx)) { - rc = efx_mdio_check_mmds(efx, efx->phy_op->mmds, 0); + rc = efx_mdio_check_mmds(efx, efx->mdio.mmds, 0); if (rc) goto out; } @@ -115,23 +113,26 @@ out: static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) { - int rc; + int rc = 0; + + if (efx->type->test_nvram) { + rc = efx->type->test_nvram(efx); + tests->nvram = rc ? -1 : 1; + } - rc = falcon_read_nvram(efx, NULL); - tests->nvram = rc ? -1 : 1; return rc; } static int efx_test_chip(struct efx_nic *efx, struct efx_self_tests *tests) { - int rc; + int rc = 0; - /* Not supported on A-series silicon */ - if (falcon_rev(efx) < FALCON_REV_B0) - return 0; + /* Test register access */ + if (efx->type->test_registers) { + rc = efx->type->test_registers(efx); + tests->registers = rc ? -1 : 1; + } - rc = falcon_test_registers(efx); - tests->registers = rc ? -1 : 1; return rc; } @@ -163,7 +164,7 @@ static int efx_test_interrupts(struct efx_nic *efx, goto success; } - falcon_generate_interrupt(efx); + efx_nic_generate_interrupt(efx); /* Wait for arrival of test interrupt. */ EFX_LOG(efx, "waiting for test interrupt\n"); @@ -201,7 +202,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel, channel->eventq_magic = 0; smp_wmb(); - falcon_generate_test_event(channel, magic); + efx_nic_generate_test_event(channel, magic); /* Wait for arrival of interrupt */ count = 0; @@ -252,9 +253,6 @@ static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, if (!efx->phy_op->run_tests) return 0; - EFX_BUG_ON_PARANOID(efx->phy_op->num_tests == 0 || - efx->phy_op->num_tests > EFX_MAX_PHY_TESTS); - mutex_lock(&efx->mac_lock); rc = efx->phy_op->run_tests(efx, tests->phy, flags); mutex_unlock(&efx->mac_lock); @@ -437,7 +435,6 @@ static int efx_begin_loopback(struct efx_tx_queue *tx_queue) kfree_skb(skb); return -EPIPE; } - efx->net_dev->trans_start = jiffies; } return 0; @@ -566,14 +563,49 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, return 0; } +/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but + * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it + * to delay and retry. Therefore, it's safer to just poll directly. Wait + * for link up and any faults to dissipate. */ +static int efx_wait_for_link(struct efx_nic *efx) +{ + struct efx_link_state *link_state = &efx->link_state; + int count; + bool link_up; + + for (count = 0; count < 40; count++) { + schedule_timeout_uninterruptible(HZ / 10); + + if (efx->type->monitor != NULL) { + mutex_lock(&efx->mac_lock); + efx->type->monitor(efx); + mutex_unlock(&efx->mac_lock); + } else { + struct efx_channel *channel = &efx->channel[0]; + if (channel->work_pending) + efx_process_channel_now(channel); + } + + mutex_lock(&efx->mac_lock); + link_up = link_state->up; + if (link_up) + link_up = !efx->mac_op->check_fault(efx); + mutex_unlock(&efx->mac_lock); + + if (link_up) + return 0; + } + + return -ETIMEDOUT; +} + static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, unsigned int loopback_modes) { enum efx_loopback_mode mode; struct efx_loopback_state *state; struct efx_tx_queue *tx_queue; - bool link_up; - int count, rc = 0; + int rc = 0; /* Set the port loopback_selftest member. From this point on * all received packets will be dropped. Mark the state as @@ -592,46 +624,23 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, /* Move the port into the specified loopback mode. */ state->flush = true; + mutex_lock(&efx->mac_lock); efx->loopback_mode = mode; - efx_reconfigure_port(efx); - - /* Wait for the PHY to signal the link is up. Interrupts - * are enabled for PHY's using LASI, otherwise we poll() - * quickly */ - count = 0; - do { - struct efx_channel *channel = &efx->channel[0]; + rc = __efx_reconfigure_port(efx); + mutex_unlock(&efx->mac_lock); + if (rc) { + EFX_ERR(efx, "unable to move into %s loopback\n", + LOOPBACK_MODE(efx)); + goto out; + } - efx->phy_op->poll(efx); - schedule_timeout_uninterruptible(HZ / 10); - if (channel->work_pending) - efx_process_channel_now(channel); - /* Wait for PHY events to be processed */ - flush_workqueue(efx->workqueue); - rmb(); - - /* We need both the phy and xaui links to be ok. - * rather than relying on the falcon_xmac irq/poll - * regime, just poll xaui directly */ - link_up = efx->link_state.up; - if (link_up && EFX_IS10G(efx) && - !falcon_xaui_link_ok(efx)) - link_up = false; - - } while ((++count < 20) && !link_up); - - /* The link should now be up. If it isn't, there is no point - * in attempting a loopback test */ - if (!link_up) { + rc = efx_wait_for_link(efx); + if (rc) { EFX_ERR(efx, "loopback %s never came up\n", LOOPBACK_MODE(efx)); - rc = -EIO; goto out; } - EFX_LOG(efx, "link came up in %s loopback in %d iterations\n", - LOOPBACK_MODE(efx), count); - /* Test every TX queue */ efx_for_each_tx_queue(tx_queue, efx) { state->offload_csum = (tx_queue->queue == @@ -665,7 +674,6 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, enum efx_loopback_mode loopback_mode = efx->loopback_mode; int phy_mode = efx->phy_mode; enum reset_type reset_method = RESET_TYPE_INVISIBLE; - struct ethtool_cmd ecmd; struct efx_channel *channel; int rc_test = 0, rc_reset = 0, rc; @@ -718,21 +726,21 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, mutex_unlock(&efx->mac_lock); /* free up all consumers of SRAM (including all the queues) */ - efx_reset_down(efx, reset_method, &ecmd); + efx_reset_down(efx, reset_method); rc = efx_test_chip(efx, tests); if (rc && !rc_test) rc_test = rc; /* reset the chip to recover from the register test */ - rc_reset = falcon_reset_hw(efx, reset_method); + rc_reset = efx->type->reset(efx, reset_method); /* Ensure that the phy is powered and out of loopback * for the bist and loopback tests */ efx->phy_mode &= ~PHY_MODE_LOW_POWER; efx->loopback_mode = LOOPBACK_NONE; - rc = efx_reset_up(efx, reset_method, &ecmd, rc_reset == 0); + rc = efx_reset_up(efx, reset_method, rc_reset == 0); if (rc && !rc_reset) rc_reset = rc; @@ -751,10 +759,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, rc_test = rc; /* restore the PHY to the previous state */ - efx->loopback_mode = loopback_mode; + mutex_lock(&efx->mac_lock); efx->phy_mode = phy_mode; efx->port_inhibited = false; - efx_ethtool_set_settings(efx->net_dev, &ecmd); + efx->loopback_mode = loopback_mode; + __efx_reconfigure_port(efx); + mutex_unlock(&efx->mac_lock); return rc_test; } diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c new file mode 100644 index 00000000000..de07a4f031b --- /dev/null +++ b/drivers/net/sfc/siena.c @@ -0,0 +1,604 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2009 Solarflare Communications Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation, incorporated herein by reference. + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/module.h> +#include "net_driver.h" +#include "bitfield.h" +#include "efx.h" +#include "nic.h" +#include "mac.h" +#include "spi.h" +#include "regs.h" +#include "io.h" +#include "phy.h" +#include "workarounds.h" +#include "mcdi.h" +#include "mcdi_pcol.h" + +/* Hardware control for SFC9000 family including SFL9021 (aka Siena). */ + +static void siena_init_wol(struct efx_nic *efx); + + +static void siena_push_irq_moderation(struct efx_channel *channel) +{ + efx_dword_t timer_cmd; + + if (channel->irq_moderation) + EFX_POPULATE_DWORD_2(timer_cmd, + FRF_CZ_TC_TIMER_MODE, + FFE_CZ_TIMER_MODE_INT_HLDOFF, + FRF_CZ_TC_TIMER_VAL, + channel->irq_moderation - 1); + else + EFX_POPULATE_DWORD_2(timer_cmd, + FRF_CZ_TC_TIMER_MODE, + FFE_CZ_TIMER_MODE_DIS, + FRF_CZ_TC_TIMER_VAL, 0); + efx_writed_page_locked(channel->efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0, + channel->channel); +} + +static void siena_push_multicast_hash(struct efx_nic *efx) +{ + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + + efx_mcdi_rpc(efx, MC_CMD_SET_MCAST_HASH, + efx->multicast_hash.byte, sizeof(efx->multicast_hash), + NULL, 0, NULL); +} + +static int siena_mdio_write(struct net_device *net_dev, + int prtad, int devad, u16 addr, u16 value) +{ + struct efx_nic *efx = netdev_priv(net_dev); + uint32_t status; + int rc; + + rc = efx_mcdi_mdio_write(efx, efx->mdio_bus, prtad, devad, + addr, value, &status); + if (rc) + return rc; + if (status != MC_CMD_MDIO_STATUS_GOOD) + return -EIO; + + return 0; +} + +static int siena_mdio_read(struct net_device *net_dev, + int prtad, int devad, u16 addr) +{ + struct efx_nic *efx = netdev_priv(net_dev); + uint16_t value; + uint32_t status; + int rc; + + rc = efx_mcdi_mdio_read(efx, efx->mdio_bus, prtad, devad, + addr, &value, &status); + if (rc) + return rc; + if (status != MC_CMD_MDIO_STATUS_GOOD) + return -EIO; + + return (int)value; +} + +/* This call is responsible for hooking in the MAC and PHY operations */ +static int siena_probe_port(struct efx_nic *efx) +{ + int rc; + + /* Hook in PHY operations table */ + efx->phy_op = &efx_mcdi_phy_ops; + + /* Set up MDIO structure for PHY */ + efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + efx->mdio.mdio_read = siena_mdio_read; + efx->mdio.mdio_write = siena_mdio_write; + + /* Fill out MDIO structure and loopback modes */ + rc = efx->phy_op->probe(efx); + if (rc != 0) + return rc; + + /* Initial assumption */ + efx->link_state.speed = 10000; + efx->link_state.fd = true; + efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; + + /* Allocate buffer for stats */ + rc = efx_nic_alloc_buffer(efx, &efx->stats_buffer, + MC_CMD_MAC_NSTATS * sizeof(u64)); + if (rc) + return rc; + EFX_LOG(efx, "stats buffer at %llx (virt %p phys %llx)\n", + (u64)efx->stats_buffer.dma_addr, + efx->stats_buffer.addr, + (u64)virt_to_phys(efx->stats_buffer.addr)); + + efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 1); + + return 0; +} + +void siena_remove_port(struct efx_nic *efx) +{ + efx_nic_free_buffer(efx, &efx->stats_buffer); +} + +static const struct efx_nic_register_test siena_register_tests[] = { + { FR_AZ_ADR_REGION, + EFX_OWORD32(0x0001FFFF, 0x0001FFFF, 0x0001FFFF, 0x0001FFFF) }, + { FR_CZ_USR_EV_CFG, + EFX_OWORD32(0x000103FF, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AZ_RX_CFG, + EFX_OWORD32(0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000) }, + { FR_AZ_TX_CFG, + EFX_OWORD32(0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF) }, + { FR_AZ_TX_RESERVED, + EFX_OWORD32(0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF) }, + { FR_AZ_SRM_TX_DC_CFG, + EFX_OWORD32(0x001FFFFF, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AZ_RX_DC_CFG, + EFX_OWORD32(0x00000003, 0x00000000, 0x00000000, 0x00000000) }, + { FR_AZ_RX_DC_PF_WM, + EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, + { FR_BZ_DP_CTRL, + EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, + { FR_BZ_RX_RSS_TKEY, + EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, + { FR_CZ_RX_RSS_IPV6_REG1, + EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, + { FR_CZ_RX_RSS_IPV6_REG2, + EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF) }, + { FR_CZ_RX_RSS_IPV6_REG3, + EFX_OWORD32(0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000) }, +}; + +static int siena_test_registers(struct efx_nic *efx) +{ + return efx_nic_test_registers(efx, siena_register_tests, + ARRAY_SIZE(siena_register_tests)); +} + +/************************************************************************** + * + * Device reset + * + ************************************************************************** + */ + +static int siena_reset_hw(struct efx_nic *efx, enum reset_type method) +{ + + if (method == RESET_TYPE_WORLD) + return efx_mcdi_reset_mc(efx); + else + return efx_mcdi_reset_port(efx); +} + +static int siena_probe_nvconfig(struct efx_nic *efx) +{ + int rc; + + rc = efx_mcdi_get_board_cfg(efx, efx->mac_address, NULL); + if (rc) + return rc; + + return 0; +} + +static int siena_probe_nic(struct efx_nic *efx) +{ + struct siena_nic_data *nic_data; + bool already_attached = 0; + int rc; + + /* Allocate storage for hardware specific data */ + nic_data = kzalloc(sizeof(struct siena_nic_data), GFP_KERNEL); + if (!nic_data) + return -ENOMEM; + efx->nic_data = nic_data; + + if (efx_nic_fpga_ver(efx) != 0) { + EFX_ERR(efx, "Siena FPGA not supported\n"); + rc = -ENODEV; + goto fail1; + } + + efx_mcdi_init(efx); + + /* Recover from a failed assertion before probing */ + rc = efx_mcdi_handle_assertion(efx); + if (rc) + goto fail1; + + rc = efx_mcdi_fwver(efx, &nic_data->fw_version, &nic_data->fw_build); + if (rc) { + EFX_ERR(efx, "Failed to read MCPU firmware version - " + "rc %d\n", rc); + goto fail1; /* MCPU absent? */ + } + + /* Let the BMC know that the driver is now in charge of link and + * filter settings. We must do this before we reset the NIC */ + rc = efx_mcdi_drv_attach(efx, true, &already_attached); + if (rc) { + EFX_ERR(efx, "Unable to register driver with MCPU\n"); + goto fail2; + } + if (already_attached) + /* Not a fatal error */ + EFX_ERR(efx, "Host already registered with MCPU\n"); + + /* Now we can reset the NIC */ + rc = siena_reset_hw(efx, RESET_TYPE_ALL); + if (rc) { + EFX_ERR(efx, "failed to reset NIC\n"); + goto fail3; + } + + siena_init_wol(efx); + + /* Allocate memory for INT_KER */ + rc = efx_nic_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t)); + if (rc) + goto fail4; + BUG_ON(efx->irq_status.dma_addr & 0x0f); + + EFX_LOG(efx, "INT_KER at %llx (virt %p phys %llx)\n", + (unsigned long long)efx->irq_status.dma_addr, + efx->irq_status.addr, + (unsigned long long)virt_to_phys(efx->irq_status.addr)); + + /* Read in the non-volatile configuration */ + rc = siena_probe_nvconfig(efx); + if (rc == -EINVAL) { + EFX_ERR(efx, "NVRAM is invalid therefore using defaults\n"); + efx->phy_type = PHY_TYPE_NONE; + efx->mdio.prtad = MDIO_PRTAD_NONE; + } else if (rc) { + goto fail5; + } + + return 0; + +fail5: + efx_nic_free_buffer(efx, &efx->irq_status); +fail4: +fail3: + efx_mcdi_drv_attach(efx, false, NULL); +fail2: +fail1: + kfree(efx->nic_data); + return rc; +} + +/* This call performs hardware-specific global initialisation, such as + * defining the descriptor cache sizes and number of RSS channels. + * It does not set up any buffers, descriptor rings or event queues. + */ +static int siena_init_nic(struct efx_nic *efx) +{ + efx_oword_t temp; + int rc; + + /* Recover from a failed assertion post-reset */ + rc = efx_mcdi_handle_assertion(efx); + if (rc) + return rc; + + /* Squash TX of packets of 16 bytes or less */ + efx_reado(efx, &temp, FR_AZ_TX_RESERVED); + EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); + efx_writeo(efx, &temp, FR_AZ_TX_RESERVED); + + /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16 + * descriptors (which is bad). + */ + efx_reado(efx, &temp, FR_AZ_TX_CFG); + EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_NO_EOP_DISC_EN, 0); + EFX_SET_OWORD_FIELD(temp, FRF_CZ_TX_FILTER_EN_BIT, 1); + efx_writeo(efx, &temp, FR_AZ_TX_CFG); + + efx_reado(efx, &temp, FR_AZ_RX_CFG); + EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_DESC_PUSH_EN, 0); + EFX_SET_OWORD_FIELD(temp, FRF_BZ_RX_INGR_EN, 1); + efx_writeo(efx, &temp, FR_AZ_RX_CFG); + + if (efx_nic_rx_xoff_thresh >= 0 || efx_nic_rx_xon_thresh >= 0) + /* No MCDI operation has been defined to set thresholds */ + EFX_ERR(efx, "ignoring RX flow control thresholds\n"); + + /* Enable event logging */ + rc = efx_mcdi_log_ctrl(efx, true, false, 0); + if (rc) + return rc; + + /* Set destination of both TX and RX Flush events */ + EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); + efx_writeo(efx, &temp, FR_BZ_DP_CTRL); + + EFX_POPULATE_OWORD_1(temp, FRF_CZ_USREV_DIS, 1); + efx_writeo(efx, &temp, FR_CZ_USR_EV_CFG); + + efx_nic_init_common(efx); + return 0; +} + +static void siena_remove_nic(struct efx_nic *efx) +{ + efx_nic_free_buffer(efx, &efx->irq_status); + + siena_reset_hw(efx, RESET_TYPE_ALL); + + /* Relinquish the device back to the BMC */ + if (efx_nic_has_mc(efx)) + efx_mcdi_drv_attach(efx, false, NULL); + + /* Tear down the private nic state */ + kfree(efx->nic_data); + efx->nic_data = NULL; +} + +#define STATS_GENERATION_INVALID ((u64)(-1)) + +static int siena_try_update_nic_stats(struct efx_nic *efx) +{ + u64 *dma_stats; + struct efx_mac_stats *mac_stats; + u64 generation_start; + u64 generation_end; + + mac_stats = &efx->mac_stats; + dma_stats = (u64 *)efx->stats_buffer.addr; + + generation_end = dma_stats[MC_CMD_MAC_GENERATION_END]; + if (generation_end == STATS_GENERATION_INVALID) + return 0; + rmb(); + +#define MAC_STAT(M, D) \ + mac_stats->M = dma_stats[MC_CMD_MAC_ ## D] + + MAC_STAT(tx_bytes, TX_BYTES); + MAC_STAT(tx_bad_bytes, TX_BAD_BYTES); + mac_stats->tx_good_bytes = (mac_stats->tx_bytes - + mac_stats->tx_bad_bytes); + MAC_STAT(tx_packets, TX_PKTS); + MAC_STAT(tx_bad, TX_BAD_FCS_PKTS); + MAC_STAT(tx_pause, TX_PAUSE_PKTS); + MAC_STAT(tx_control, TX_CONTROL_PKTS); + MAC_STAT(tx_unicast, TX_UNICAST_PKTS); + MAC_STAT(tx_multicast, TX_MULTICAST_PKTS); + MAC_STAT(tx_broadcast, TX_BROADCAST_PKTS); + MAC_STAT(tx_lt64, TX_LT64_PKTS); + MAC_STAT(tx_64, TX_64_PKTS); + MAC_STAT(tx_65_to_127, TX_65_TO_127_PKTS); + MAC_STAT(tx_128_to_255, TX_128_TO_255_PKTS); + MAC_STAT(tx_256_to_511, TX_256_TO_511_PKTS); + MAC_STAT(tx_512_to_1023, TX_512_TO_1023_PKTS); + MAC_STAT(tx_1024_to_15xx, TX_1024_TO_15XX_PKTS); + MAC_STAT(tx_15xx_to_jumbo, TX_15XX_TO_JUMBO_PKTS); + MAC_STAT(tx_gtjumbo, TX_GTJUMBO_PKTS); + mac_stats->tx_collision = 0; + MAC_STAT(tx_single_collision, TX_SINGLE_COLLISION_PKTS); + MAC_STAT(tx_multiple_collision, TX_MULTIPLE_COLLISION_PKTS); + MAC_STAT(tx_excessive_collision, TX_EXCESSIVE_COLLISION_PKTS); + MAC_STAT(tx_deferred, TX_DEFERRED_PKTS); + MAC_STAT(tx_late_collision, TX_LATE_COLLISION_PKTS); + mac_stats->tx_collision = (mac_stats->tx_single_collision + + mac_stats->tx_multiple_collision + + mac_stats->tx_excessive_collision + + mac_stats->tx_late_collision); + MAC_STAT(tx_excessive_deferred, TX_EXCESSIVE_DEFERRED_PKTS); + MAC_STAT(tx_non_tcpudp, TX_NON_TCPUDP_PKTS); + MAC_STAT(tx_mac_src_error, TX_MAC_SRC_ERR_PKTS); + MAC_STAT(tx_ip_src_error, TX_IP_SRC_ERR_PKTS); + MAC_STAT(rx_bytes, RX_BYTES); + MAC_STAT(rx_bad_bytes, RX_BAD_BYTES); + mac_stats->rx_good_bytes = (mac_stats->rx_bytes - + mac_stats->rx_bad_bytes); + MAC_STAT(rx_packets, RX_PKTS); + MAC_STAT(rx_good, RX_GOOD_PKTS); + mac_stats->rx_bad = mac_stats->rx_packets - mac_stats->rx_good; + MAC_STAT(rx_pause, RX_PAUSE_PKTS); + MAC_STAT(rx_control, RX_CONTROL_PKTS); + MAC_STAT(rx_unicast, RX_UNICAST_PKTS); + MAC_STAT(rx_multicast, RX_MULTICAST_PKTS); + MAC_STAT(rx_broadcast, RX_BROADCAST_PKTS); + MAC_STAT(rx_lt64, RX_UNDERSIZE_PKTS); + MAC_STAT(rx_64, RX_64_PKTS); + MAC_STAT(rx_65_to_127, RX_65_TO_127_PKTS); + MAC_STAT(rx_128_to_255, RX_128_TO_255_PKTS); + MAC_STAT(rx_256_to_511, RX_256_TO_511_PKTS); + MAC_STAT(rx_512_to_1023, RX_512_TO_1023_PKTS); + MAC_STAT(rx_1024_to_15xx, RX_1024_TO_15XX_PKTS); + MAC_STAT(rx_15xx_to_jumbo, RX_15XX_TO_JUMBO_PKTS); + MAC_STAT(rx_gtjumbo, RX_GTJUMBO_PKTS); + mac_stats->rx_bad_lt64 = 0; + mac_stats->rx_bad_64_to_15xx = 0; + mac_stats->rx_bad_15xx_to_jumbo = 0; + MAC_STAT(rx_bad_gtjumbo, RX_JABBER_PKTS); + MAC_STAT(rx_overflow, RX_OVERFLOW_PKTS); + mac_stats->rx_missed = 0; + MAC_STAT(rx_false_carrier, RX_FALSE_CARRIER_PKTS); + MAC_STAT(rx_symbol_error, RX_SYMBOL_ERROR_PKTS); + MAC_STAT(rx_align_error, RX_ALIGN_ERROR_PKTS); + MAC_STAT(rx_length_error, RX_LENGTH_ERROR_PKTS); + MAC_STAT(rx_internal_error, RX_INTERNAL_ERROR_PKTS); + mac_stats->rx_good_lt64 = 0; + + efx->n_rx_nodesc_drop_cnt = dma_stats[MC_CMD_MAC_RX_NODESC_DROPS]; + +#undef MAC_STAT + + rmb(); + generation_start = dma_stats[MC_CMD_MAC_GENERATION_START]; + if (generation_end != generation_start) + return -EAGAIN; + + return 0; +} + +static void siena_update_nic_stats(struct efx_nic *efx) +{ + while (siena_try_update_nic_stats(efx) == -EAGAIN) + cpu_relax(); +} + +static void siena_start_nic_stats(struct efx_nic *efx) +{ + u64 *dma_stats = (u64 *)efx->stats_buffer.addr; + + dma_stats[MC_CMD_MAC_GENERATION_END] = STATS_GENERATION_INVALID; + + efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, + MC_CMD_MAC_NSTATS * sizeof(u64), 1, 0); +} + +static void siena_stop_nic_stats(struct efx_nic *efx) +{ + efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 0); +} + +void siena_print_fwver(struct efx_nic *efx, char *buf, size_t len) +{ + struct siena_nic_data *nic_data = efx->nic_data; + snprintf(buf, len, "%u.%u.%u.%u", + (unsigned int)(nic_data->fw_version >> 48), + (unsigned int)(nic_data->fw_version >> 32 & 0xffff), + (unsigned int)(nic_data->fw_version >> 16 & 0xffff), + (unsigned int)(nic_data->fw_version & 0xffff)); +} + +/************************************************************************** + * + * Wake on LAN + * + ************************************************************************** + */ + +static void siena_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol) +{ + struct siena_nic_data *nic_data = efx->nic_data; + + wol->supported = WAKE_MAGIC; + if (nic_data->wol_filter_id != -1) + wol->wolopts = WAKE_MAGIC; + else + wol->wolopts = 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + + +static int siena_set_wol(struct efx_nic *efx, u32 type) +{ + struct siena_nic_data *nic_data = efx->nic_data; + int rc; + + if (type & ~WAKE_MAGIC) + return -EINVAL; + + if (type & WAKE_MAGIC) { + if (nic_data->wol_filter_id != -1) + efx_mcdi_wol_filter_remove(efx, + nic_data->wol_filter_id); + rc = efx_mcdi_wol_filter_set_magic(efx, efx->mac_address, + &nic_data->wol_filter_id); + if (rc) + goto fail; + + pci_wake_from_d3(efx->pci_dev, true); + } else { + rc = efx_mcdi_wol_filter_reset(efx); + nic_data->wol_filter_id = -1; + pci_wake_from_d3(efx->pci_dev, false); + if (rc) + goto fail; + } + + return 0; + fail: + EFX_ERR(efx, "%s failed: type=%d rc=%d\n", __func__, type, rc); + return rc; +} + + +static void siena_init_wol(struct efx_nic *efx) +{ + struct siena_nic_data *nic_data = efx->nic_data; + int rc; + + rc = efx_mcdi_wol_filter_get_magic(efx, &nic_data->wol_filter_id); + + if (rc != 0) { + /* If it failed, attempt to get into a synchronised + * state with MC by resetting any set WoL filters */ + efx_mcdi_wol_filter_reset(efx); + nic_data->wol_filter_id = -1; + } else if (nic_data->wol_filter_id != -1) { + pci_wake_from_d3(efx->pci_dev, true); + } +} + + +/************************************************************************** + * + * Revision-dependent attributes used by efx.c and nic.c + * + ************************************************************************** + */ + +struct efx_nic_type siena_a0_nic_type = { + .probe = siena_probe_nic, + .remove = siena_remove_nic, + .init = siena_init_nic, + .fini = efx_port_dummy_op_void, + .monitor = NULL, + .reset = siena_reset_hw, + .probe_port = siena_probe_port, + .remove_port = siena_remove_port, + .prepare_flush = efx_port_dummy_op_void, + .update_stats = siena_update_nic_stats, + .start_stats = siena_start_nic_stats, + .stop_stats = siena_stop_nic_stats, + .set_id_led = efx_mcdi_set_id_led, + .push_irq_moderation = siena_push_irq_moderation, + .push_multicast_hash = siena_push_multicast_hash, + .reconfigure_port = efx_mcdi_phy_reconfigure, + .get_wol = siena_get_wol, + .set_wol = siena_set_wol, + .resume_wol = siena_init_wol, + .test_registers = siena_test_registers, + .default_mac_ops = &efx_mcdi_mac_operations, + + .revision = EFX_REV_SIENA_A0, + .mem_map_size = (FR_CZ_MC_TREG_SMEM + + FR_CZ_MC_TREG_SMEM_STEP * FR_CZ_MC_TREG_SMEM_ROWS), + .txd_ptr_tbl_base = FR_BZ_TX_DESC_PTR_TBL, + .rxd_ptr_tbl_base = FR_BZ_RX_DESC_PTR_TBL, + .buf_tbl_base = FR_BZ_BUF_FULL_TBL, + .evq_ptr_tbl_base = FR_BZ_EVQ_PTR_TBL, + .evq_rptr_tbl_base = FR_BZ_EVQ_RPTR, + .max_dma_mask = DMA_BIT_MASK(FSF_AZ_TX_KER_BUF_ADDR_WIDTH), + .rx_buffer_padding = 0, + .max_interrupt_mode = EFX_INT_MODE_MSIX, + .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy + * interrupt handler only supports 32 + * channels */ + .tx_dc_base = 0x88000, + .rx_dc_base = 0x68000, + .offload_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM, + .reset_world_flags = ETH_RESET_MGMT << ETH_RESET_SHARED_SHIFT, +}; diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h index 1b1ceb41167..8bf4fce0813 100644 --- a/drivers/net/sfc/spi.h +++ b/drivers/net/sfc/spi.h @@ -36,8 +36,6 @@ /** * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device - * @efx: The Efx controller that owns this device - * @mtd: MTD state * @device_id: Controller's id for the device * @size: Size (in bytes) * @addr_len: Number of address bytes in read/write commands @@ -54,10 +52,6 @@ * Write commands are limited to blocks with this size and alignment. */ struct efx_spi_device { - struct efx_nic *efx; -#ifdef CONFIG_SFC_MTD - void *mtd; -#endif int device_id; unsigned int size; unsigned int addr_len; @@ -67,12 +61,16 @@ struct efx_spi_device { unsigned int block_size; }; -int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command, +int falcon_spi_cmd(struct efx_nic *efx, + const struct efx_spi_device *spi, unsigned int command, int address, const void* in, void *out, size_t len); -int falcon_spi_wait_write(const struct efx_spi_device *spi); -int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, +int falcon_spi_wait_write(struct efx_nic *efx, + const struct efx_spi_device *spi); +int falcon_spi_read(struct efx_nic *efx, + const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, u8 *buffer); -int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, +int falcon_spi_write(struct efx_nic *efx, + const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, const u8 *buffer); /* diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index b001f38524f..ca11572a49a 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007-2008 Solarflare Communications Inc. + * Copyright 2007-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -12,7 +12,7 @@ #include <linux/seq_file.h> #include "efx.h" #include "mdio_10g.h" -#include "falcon.h" +#include "nic.h" #include "phy.h" #include "regs.h" #include "workarounds.h" @@ -30,13 +30,13 @@ #define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ (1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PMAPMD) | \ - (1 << LOOPBACK_NETWORK)) + (1 << LOOPBACK_PHYXS_WS)) #define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) | \ (1 << LOOPBACK_PHYXS) | \ (1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PMAPMD) | \ - (1 << LOOPBACK_NETWORK)) + (1 << LOOPBACK_PHYXS_WS)) /* We complain if we fail to see the link partner as 10G capable this many * times in a row (must be > 1 as sampling the autoneg. registers is racy) @@ -199,15 +199,16 @@ static ssize_t set_phy_short_reach(struct device *dev, const char *buf, size_t count) { struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + int rc; rtnl_lock(); efx_mdio_set_flag(efx, MDIO_MMD_PMAPMD, MDIO_PMA_10GBT_TXPWR, MDIO_PMA_10GBT_TXPWR_SHORT, count != 0 && *buf != '0'); - efx_reconfigure_port(efx); + rc = efx_reconfigure_port(efx); rtnl_unlock(); - return count; + return rc < 0 ? rc : (ssize_t)count; } static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach, @@ -297,13 +298,29 @@ static int tenxpress_init(struct efx_nic *efx) return 0; } +static int sfx7101_phy_probe(struct efx_nic *efx) +{ + efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; + efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + efx->loopback_modes = SFX7101_LOOPBACKS | FALCON_XMAC_LOOPBACKS; + return 0; +} + +static int sft9001_phy_probe(struct efx_nic *efx) +{ + efx->mdio.mmds = TENXPRESS_REQUIRED_DEVS; + efx->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + efx->loopback_modes = (SFT9001_LOOPBACKS | FALCON_XMAC_LOOPBACKS | + FALCON_GMAC_LOOPBACKS); + return 0; +} + static int tenxpress_phy_init(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data; - u16 old_adv, adv; int rc = 0; - falcon_board(efx)->init_phy(efx); + falcon_board(efx)->type->init_phy(efx); phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL); if (!phy_data) @@ -335,14 +352,14 @@ static int tenxpress_phy_init(struct efx_nic *efx) if (rc < 0) goto fail; - /* Set pause advertising */ - old_adv = efx_mdio_read(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE); - adv = ((old_adv & ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM)) | - mii_advertise_flowctrl(efx->wanted_fc)); - if (adv != old_adv) { - efx_mdio_write(efx, MDIO_MMD_AN, MDIO_AN_ADVERTISE, adv); - mdio45_nway_restart(&efx->mdio); - } + /* Initialise advertising flags */ + efx->link_advertising = (ADVERTISED_TP | ADVERTISED_Autoneg | + ADVERTISED_10000baseT_Full); + if (efx->phy_type != PHY_TYPE_SFX7101) + efx->link_advertising |= (ADVERTISED_1000baseT_Full | + ADVERTISED_100baseT_Full); + efx_link_set_wanted_fc(efx, efx->wanted_fc); + efx_mdio_an_reconfigure(efx); if (efx->phy_type == PHY_TYPE_SFT9001B) { rc = device_create_file(&efx->pci_dev->dev, @@ -374,7 +391,7 @@ static int tenxpress_special_reset(struct efx_nic *efx) /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so * a special software reset can glitch the XGMAC sufficiently for stats * requests to fail. */ - efx_stats_disable(efx); + falcon_stop_nic_stats(efx); /* Initiate reset */ reg = efx_mdio_read(efx, MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); @@ -396,7 +413,7 @@ static int tenxpress_special_reset(struct efx_nic *efx) /* Wait for the XGXS state machine to churn */ mdelay(10); out: - efx_stats_enable(efx); + falcon_start_nic_stats(efx); return rc; } @@ -500,97 +517,76 @@ static void tenxpress_low_power(struct efx_nic *efx) !!(efx->phy_mode & PHY_MODE_LOW_POWER)); } -static void tenxpress_phy_reconfigure(struct efx_nic *efx) +static int tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; - struct efx_link_state *link_state = &efx->link_state; - struct ethtool_cmd ecmd; bool phy_mode_change, loop_reset; if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; - return; + return 0; } - tenxpress_low_power(efx); - phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && phy_data->phy_mode != PHY_MODE_NORMAL); - loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) || + loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, LOOPBACKS_EXTERNAL(efx)) || LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); if (loop_reset || phy_mode_change) { - int rc; + tenxpress_special_reset(efx); - efx->phy_op->get_settings(efx, &ecmd); - - if (loop_reset || phy_mode_change) { - tenxpress_special_reset(efx); - - /* Reset XAUI if we were in 10G, and are staying - * in 10G. If we're moving into and out of 10G - * then xaui will be reset anyway */ - if (EFX_IS10G(efx)) - falcon_reset_xaui(efx); - } - - rc = efx->phy_op->set_settings(efx, &ecmd); - WARN_ON(rc); + /* Reset XAUI if we were in 10G, and are staying + * in 10G. If we're moving into and out of 10G + * then xaui will be reset anyway */ + if (EFX_IS10G(efx)) + falcon_reset_xaui(efx); } + tenxpress_low_power(efx); efx_mdio_transmit_disable(efx); efx_mdio_phy_reconfigure(efx); tenxpress_ext_loopback(efx); + efx_mdio_an_reconfigure(efx); phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; - if (efx->phy_type == PHY_TYPE_SFX7101) { - link_state->speed = 10000; - link_state->fd = true; - link_state->up = sfx7101_link_ok(efx); - } else { - efx->phy_op->get_settings(efx, &ecmd); - link_state->speed = ecmd.speed; - link_state->fd = ecmd.duplex == DUPLEX_FULL; - link_state->up = sft9001_link_ok(efx, &ecmd); - } - link_state->fc = efx_mdio_get_pause(efx); + return 0; } -/* Poll PHY for interrupt */ -static void tenxpress_phy_poll(struct efx_nic *efx) +static void +tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); + +/* Poll for link state changes */ +static bool tenxpress_phy_poll(struct efx_nic *efx) { - struct tenxpress_phy_data *phy_data = efx->phy_data; - struct efx_link_state *link_state = &efx->link_state; - bool change = false; + struct efx_link_state old_state = efx->link_state; if (efx->phy_type == PHY_TYPE_SFX7101) { - bool link_ok = sfx7101_link_ok(efx); - if (link_ok != link_state->up) { - change = true; - } else { - unsigned int link_fc = efx_mdio_get_pause(efx); - if (link_fc != link_state->fc) - change = true; - } - sfx7101_check_bad_lp(efx, link_ok); - } else if (efx->loopback_mode) { - bool link_ok = sft9001_link_ok(efx, NULL); - if (link_ok != link_state->up) - change = true; + efx->link_state.up = sfx7101_link_ok(efx); + efx->link_state.speed = 10000; + efx->link_state.fd = true; + efx->link_state.fc = efx_mdio_get_pause(efx); + + sfx7101_check_bad_lp(efx, efx->link_state.up); } else { - int status = efx_mdio_read(efx, MDIO_MMD_PMAPMD, - MDIO_PMA_LASI_STAT); - if (status & MDIO_PMA_LASI_LSALARM) - change = true; - } + struct ethtool_cmd ecmd; - if (change) - falcon_sim_phy_event(efx); + /* Check the LASI alarm first */ + if (efx->loopback_mode == LOOPBACK_NONE && + !(efx_mdio_read(efx, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT) & + MDIO_PMA_LASI_LSALARM)) + return false; - if (phy_data->phy_mode != PHY_MODE_NORMAL) - return; + tenxpress_get_settings(efx, &ecmd); + + efx->link_state.up = sft9001_link_ok(efx, &ecmd); + efx->link_state.speed = ecmd.speed; + efx->link_state.fd = (ecmd.duplex == DUPLEX_FULL); + efx->link_state.fc = efx_mdio_get_pause(efx); + } + + return !efx_link_state_equal(&efx->link_state, &old_state); } static void tenxpress_phy_fini(struct efx_nic *efx) @@ -648,6 +644,13 @@ static const char *const sfx7101_test_names[] = { "bist" }; +static const char *sfx7101_test_name(struct efx_nic *efx, unsigned int index) +{ + if (index < ARRAY_SIZE(sfx7101_test_names)) + return sfx7101_test_names[index]; + return NULL; +} + static int sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) { @@ -659,6 +662,9 @@ sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) /* BIST is automatically run after a special software reset */ rc = tenxpress_special_reset(efx); results[0] = rc ? -1 : 1; + + efx_mdio_an_reconfigure(efx); + return rc; } @@ -674,14 +680,17 @@ static const char *const sft9001_test_names[] = { "cable.pairD.length", }; +static const char *sft9001_test_name(struct efx_nic *efx, unsigned int index) +{ + if (index < ARRAY_SIZE(sft9001_test_names)) + return sft9001_test_names[index]; + return NULL; +} + static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) { - struct ethtool_cmd ecmd; int rc = 0, rc2, i, ctrl_reg, res_reg; - if (flags & ETH_TEST_FL_OFFLINE) - efx->phy_op->get_settings(efx, &ecmd); - /* Initialise cable diagnostic results to unknown failure */ for (i = 1; i < 9; ++i) results[i] = -1; @@ -733,9 +742,7 @@ out: if (!rc) rc = rc2; - rc2 = efx->phy_op->set_settings(efx, &ecmd); - if (!rc) - rc = rc2; + efx_mdio_an_reconfigure(efx); } return rc; @@ -766,7 +773,6 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) mdio45_ethtool_gset_npage(&efx->mdio, ecmd, adv, lpa); - ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; if (efx->phy_type != PHY_TYPE_SFX7101) { ecmd->supported |= (SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full); @@ -783,7 +789,7 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) * but doesn't advertise the correct speed. So override it */ if (efx->loopback_mode == LOOPBACK_GPHY) ecmd->speed = SPEED_1000; - else if (LOOPBACK_MASK(efx) & efx->phy_op->loopbacks) + else if (LOOPBACK_EXTERNAL(efx)) ecmd->speed = SPEED_10000; } @@ -813,35 +819,27 @@ static void sft9001_set_npage_adv(struct efx_nic *efx, u32 advertising) } struct efx_phy_operations falcon_sfx7101_phy_ops = { - .macs = EFX_XMAC, + .probe = sfx7101_phy_probe, .init = tenxpress_phy_init, .reconfigure = tenxpress_phy_reconfigure, .poll = tenxpress_phy_poll, .fini = tenxpress_phy_fini, - .clear_interrupt = efx_port_dummy_op_void, .get_settings = tenxpress_get_settings, .set_settings = tenxpress_set_settings, .set_npage_adv = sfx7101_set_npage_adv, - .num_tests = ARRAY_SIZE(sfx7101_test_names), - .test_names = sfx7101_test_names, + .test_name = sfx7101_test_name, .run_tests = sfx7101_run_tests, - .mmds = TENXPRESS_REQUIRED_DEVS, - .loopbacks = SFX7101_LOOPBACKS, }; struct efx_phy_operations falcon_sft9001_phy_ops = { - .macs = EFX_GMAC | EFX_XMAC, + .probe = sft9001_phy_probe, .init = tenxpress_phy_init, .reconfigure = tenxpress_phy_reconfigure, .poll = tenxpress_phy_poll, .fini = tenxpress_phy_fini, - .clear_interrupt = efx_port_dummy_op_void, .get_settings = tenxpress_get_settings, .set_settings = tenxpress_set_settings, .set_npage_adv = sft9001_set_npage_adv, - .num_tests = ARRAY_SIZE(sft9001_test_names), - .test_names = sft9001_test_names, + .test_name = sft9001_test_name, .run_tests = sft9001_run_tests, - .mmds = TENXPRESS_REQUIRED_DEVS, - .loopbacks = SFT9001_LOOPBACKS, }; diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c index c54fa30e627..e669f94e821 100644 --- a/drivers/net/sfc/tx.c +++ b/drivers/net/sfc/tx.c @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2005-2008 Solarflare Communications Inc. + * Copyright 2005-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -12,11 +12,13 @@ #include <linux/tcp.h> #include <linux/ip.h> #include <linux/in.h> +#include <linux/ipv6.h> +#include <net/ipv6.h> #include <linux/if_ether.h> #include <linux/highmem.h> #include "net_driver.h" #include "efx.h" -#include "falcon.h" +#include "nic.h" #include "workarounds.h" /* @@ -278,7 +280,7 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) buffer->continuation = false; /* Pass off to hardware */ - falcon_push_buffers(tx_queue); + efx_nic_push_buffers(tx_queue); return NETDEV_TX_OK; @@ -426,7 +428,7 @@ int efx_probe_tx_queue(struct efx_tx_queue *tx_queue) tx_queue->buffer[i].continuation = true; /* Allocate hardware ring */ - rc = falcon_probe_tx(tx_queue); + rc = efx_nic_probe_tx(tx_queue); if (rc) goto fail; @@ -449,7 +451,7 @@ void efx_init_tx_queue(struct efx_tx_queue *tx_queue) BUG_ON(tx_queue->stopped); /* Set up TX descriptor ring */ - falcon_init_tx(tx_queue); + efx_nic_init_tx(tx_queue); } void efx_release_tx_buffers(struct efx_tx_queue *tx_queue) @@ -475,7 +477,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue); /* Flush TX queue, remove descriptor ring */ - falcon_fini_tx(tx_queue); + efx_nic_fini_tx(tx_queue); efx_release_tx_buffers(tx_queue); @@ -492,7 +494,7 @@ void efx_fini_tx_queue(struct efx_tx_queue *tx_queue) void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) { EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue); - falcon_remove_tx(tx_queue); + efx_nic_remove_tx(tx_queue); kfree(tx_queue->buffer); tx_queue->buffer = NULL; @@ -531,6 +533,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) #define ETH_HDR_LEN(skb) (skb_network_header(skb) - (skb)->data) #define SKB_TCP_OFF(skb) PTR_DIFF(tcp_hdr(skb), (skb)->data) #define SKB_IPV4_OFF(skb) PTR_DIFF(ip_hdr(skb), (skb)->data) +#define SKB_IPV6_OFF(skb) PTR_DIFF(ipv6_hdr(skb), (skb)->data) /** * struct tso_state - TSO state for an SKB @@ -543,6 +546,7 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) * @unmap_len: Length of SKB fragment * @unmap_addr: DMA address of SKB fragment * @unmap_single: DMA single vs page mapping flag + * @protocol: Network protocol (after any VLAN header) * @header_len: Number of bytes of header * @full_packet_size: Number of bytes to put in each outgoing segment * @@ -563,6 +567,7 @@ struct tso_state { dma_addr_t unmap_addr; bool unmap_single; + __be16 protocol; unsigned header_len; int full_packet_size; }; @@ -570,9 +575,9 @@ struct tso_state { /* * Verify that our various assumptions about sk_buffs and the conditions - * under which TSO will be attempted hold true. + * under which TSO will be attempted hold true. Return the protocol number. */ -static void efx_tso_check_safe(struct sk_buff *skb) +static __be16 efx_tso_check_protocol(struct sk_buff *skb) { __be16 protocol = skb->protocol; @@ -587,13 +592,22 @@ static void efx_tso_check_safe(struct sk_buff *skb) if (protocol == htons(ETH_P_IP)) skb_set_transport_header(skb, sizeof(*veh) + 4 * ip_hdr(skb)->ihl); + else if (protocol == htons(ETH_P_IPV6)) + skb_set_transport_header(skb, sizeof(*veh) + + sizeof(struct ipv6hdr)); } - EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IP)); - EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); + if (protocol == htons(ETH_P_IP)) { + EFX_BUG_ON_PARANOID(ip_hdr(skb)->protocol != IPPROTO_TCP); + } else { + EFX_BUG_ON_PARANOID(protocol != htons(ETH_P_IPV6)); + EFX_BUG_ON_PARANOID(ipv6_hdr(skb)->nexthdr != NEXTHDR_TCP); + } EFX_BUG_ON_PARANOID((PTR_DIFF(tcp_hdr(skb), skb->data) + (tcp_hdr(skb)->doff << 2u)) > skb_headlen(skb)); + + return protocol; } @@ -836,7 +850,10 @@ static void tso_start(struct tso_state *st, const struct sk_buff *skb) + PTR_DIFF(tcp_hdr(skb), skb->data)); st->full_packet_size = st->header_len + skb_shinfo(skb)->gso_size; - st->ipv4_id = ntohs(ip_hdr(skb)->id); + if (st->protocol == htons(ETH_P_IP)) + st->ipv4_id = ntohs(ip_hdr(skb)->id); + else + st->ipv4_id = 0; st->seqnum = ntohl(tcp_hdr(skb)->seq); EFX_BUG_ON_PARANOID(tcp_hdr(skb)->urg); @@ -951,7 +968,6 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, struct tso_state *st) { struct efx_tso_header *tsoh; - struct iphdr *tsoh_iph; struct tcphdr *tsoh_th; unsigned ip_length; u8 *header; @@ -975,7 +991,6 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, header = TSOH_BUFFER(tsoh); tsoh_th = (struct tcphdr *)(header + SKB_TCP_OFF(skb)); - tsoh_iph = (struct iphdr *)(header + SKB_IPV4_OFF(skb)); /* Copy and update the headers. */ memcpy(header, skb->data, st->header_len); @@ -993,11 +1008,22 @@ static int tso_start_new_packet(struct efx_tx_queue *tx_queue, tsoh_th->fin = tcp_hdr(skb)->fin; tsoh_th->psh = tcp_hdr(skb)->psh; } - tsoh_iph->tot_len = htons(ip_length); - /* Linux leaves suitable gaps in the IP ID space for us to fill. */ - tsoh_iph->id = htons(st->ipv4_id); - st->ipv4_id++; + if (st->protocol == htons(ETH_P_IP)) { + struct iphdr *tsoh_iph = + (struct iphdr *)(header + SKB_IPV4_OFF(skb)); + + tsoh_iph->tot_len = htons(ip_length); + + /* Linux leaves suitable gaps in the IP ID space for us to fill. */ + tsoh_iph->id = htons(st->ipv4_id); + st->ipv4_id++; + } else { + struct ipv6hdr *tsoh_iph = + (struct ipv6hdr *)(header + SKB_IPV6_OFF(skb)); + + tsoh_iph->payload_len = htons(ip_length - sizeof(*tsoh_iph)); + } st->packet_space = skb_shinfo(skb)->gso_size; ++tx_queue->tso_packets; @@ -1027,8 +1053,8 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, int frag_i, rc, rc2 = NETDEV_TX_OK; struct tso_state state; - /* Verify TSO is safe - these checks should never fail. */ - efx_tso_check_safe(skb); + /* Find the packet protocol and sanity-check it */ + state.protocol = efx_tso_check_protocol(skb); EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count); @@ -1078,7 +1104,7 @@ static int efx_enqueue_skb_tso(struct efx_tx_queue *tx_queue, } /* Pass off to hardware */ - falcon_push_buffers(tx_queue); + efx_nic_push_buffers(tx_queue); tx_queue->tso_bursts++; return NETDEV_TX_OK; diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index 32502994948..acd9c734e48 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2006-2008 Solarflare Communications Inc. + * Copyright 2006-2009 Solarflare Communications Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published @@ -16,7 +16,9 @@ */ #define EFX_WORKAROUND_ALWAYS(efx) 1 -#define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1) +#define EFX_WORKAROUND_FALCON_A(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) +#define EFX_WORKAROUND_FALCON_AB(efx) (efx_nic_rev(efx) <= EFX_REV_FALCON_B0) +#define EFX_WORKAROUND_SIENA(efx) (efx_nic_rev(efx) == EFX_REV_SIENA_A0) #define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) #define EFX_WORKAROUND_SFT9001(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A || \ (efx)->phy_type == PHY_TYPE_SFT9001B) @@ -27,17 +29,17 @@ #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS /* Bit-bashed I2C reads cause performance drop */ #define EFX_WORKAROUND_7884 EFX_WORKAROUND_10G -/* TX pkt parser problem with <= 16 byte TXes */ -#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor * or a PCIe error (bug 11028) */ #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS /* Transmit flow control may get disabled */ -#define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS -/* Flush events can take a very long time to appear */ -#define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS +#define EFX_WORKAROUND_11482 EFX_WORKAROUND_FALCON_AB /* Truncated IPv4 packets can confuse the TX packet parser */ -#define EFX_WORKAROUND_15592 EFX_WORKAROUND_ALWAYS +#define EFX_WORKAROUND_15592 EFX_WORKAROUND_FALCON_AB +/* Legacy ISR read can return zero once */ +#define EFX_WORKAROUND_15783 EFX_WORKAROUND_SIENA +/* Legacy interrupt storm when interrupt fifo fills */ +#define EFX_WORKAROUND_17213 EFX_WORKAROUND_SIENA /* Spurious parity errors in TSORT buffers */ #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 34b4e7d500d..379a3dc0016 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -238,8 +238,8 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; - if ((wol->wolopts & ~wol_supported(hw)) - || !device_can_wakeup(&hw->pdev->dev)) + if ((wol->wolopts & ~wol_supported(hw)) || + !device_can_wakeup(&hw->pdev->dev)) return -EOPNOTSUPP; skge->wol = wol->wolopts; @@ -576,9 +576,10 @@ static void skge_get_pauseparam(struct net_device *dev, { struct skge_port *skge = netdev_priv(dev); - ecmd->rx_pause = (skge->flow_control == FLOW_MODE_SYMMETRIC) - || (skge->flow_control == FLOW_MODE_SYM_OR_REM); - ecmd->tx_pause = ecmd->rx_pause || (skge->flow_control == FLOW_MODE_LOC_SEND); + ecmd->rx_pause = ((skge->flow_control == FLOW_MODE_SYMMETRIC) || + (skge->flow_control == FLOW_MODE_SYM_OR_REM)); + ecmd->tx_pause = (ecmd->rx_pause || + (skge->flow_control == FLOW_MODE_LOC_SEND)); ecmd->autoneg = ecmd->rx_pause || ecmd->tx_pause; } @@ -2779,8 +2780,8 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, /* This seems backwards, but it is what the sk98lin * does. Looks like hardware is wrong? */ - if (ipip_hdr(skb)->protocol == IPPROTO_UDP - && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON) + if (ipip_hdr(skb)->protocol == IPPROTO_UDP && + hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON) control = BMU_TCP_CHECK; else control = BMU_UDP_CHECK; @@ -2948,8 +2949,8 @@ static void genesis_set_multicast(struct net_device *dev) else { memset(filter, 0, sizeof(filter)); - if (skge->flow_status == FLOW_STAT_REM_SEND - || skge->flow_status == FLOW_STAT_SYMMETRIC) + if (skge->flow_status == FLOW_STAT_REM_SEND || + skge->flow_status == FLOW_STAT_SYMMETRIC) genesis_add_filter(filter, pause_mc_addr); for (i = 0; list && i < count; i++, list = list->next) @@ -2972,8 +2973,8 @@ static void yukon_set_multicast(struct net_device *dev) struct skge_hw *hw = skge->hw; int port = skge->port; struct dev_mc_list *list = dev->mc_list; - int rx_pause = (skge->flow_status == FLOW_STAT_REM_SEND - || skge->flow_status == FLOW_STAT_SYMMETRIC); + int rx_pause = (skge->flow_status == FLOW_STAT_REM_SEND || + skge->flow_status == FLOW_STAT_SYMMETRIC); u16 reg; u8 filter[8]; diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index a3d99913f18..3943d89afb2 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -374,8 +374,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO); /* downshift on PHY 88E1112 and 88E1149 is changed */ - if ( (sky2->flags & SKY2_FLAG_AUTO_SPEED) - && (hw->flags & SKY2_HW_NEWER_PHY)) { + if ( (sky2->flags & SKY2_FLAG_AUTO_SPEED) && + (hw->flags & SKY2_HW_NEWER_PHY)) { /* set downshift counter to 3x and enable downshift */ ctrl &= ~PHY_M_PC_DSC_MSK; ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA; @@ -619,8 +619,8 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* no effect on Yukon-XL */ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); - if ( !(sky2->flags & SKY2_FLAG_AUTO_SPEED) - || sky2->speed == SPEED_100) { + if (!(sky2->flags & SKY2_FLAG_AUTO_SPEED) || + sky2->speed == SPEED_100) { /* turn on 100 Mbps LED (LED_LINK100) */ ledover |= PHY_M_LED_MO_100(MO_LED_ON); } @@ -937,8 +937,8 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) /* On chips without ram buffer, pause is controled by MAC level */ if (!(hw->flags & SKY2_HW_RAM_BUFFER)) { /* Pause threshold is scaled by 8 in bytes */ - if (hw->chip_id == CHIP_ID_YUKON_FE_P - && hw->chip_rev == CHIP_REV_YU_FE2_A0) + if (hw->chip_id == CHIP_ID_YUKON_FE_P && + hw->chip_rev == CHIP_REV_YU_FE2_A0) reg = 1568 / 8; else reg = 1024 / 8; @@ -1353,8 +1353,8 @@ static int sky2_rx_start(struct sky2_port *sky2) /* These chips have no ram buffer? * MAC Rx RAM Read is controlled by hardware */ if (hw->chip_id == CHIP_ID_YUKON_EC_U && - (hw->chip_rev == CHIP_REV_YU_EC_U_A1 - || hw->chip_rev == CHIP_REV_YU_EC_U_B0)) + (hw->chip_rev == CHIP_REV_YU_EC_U_A1 || + hw->chip_rev == CHIP_REV_YU_EC_U_B0)) sky2_write32(hw, Q_ADDR(rxq, Q_TEST), F_M_RX_RAM_DIS); sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1); @@ -1560,8 +1560,8 @@ static int sky2_up(struct net_device *dev) sky2_write32(hw, Q_ADDR(txqaddr[port], Q_TEST), F_TX_CHK_AUTO_OFF); /* Set almost empty threshold */ - if (hw->chip_id == CHIP_ID_YUKON_EC_U - && hw->chip_rev == CHIP_REV_YU_EC_U_A0) + if (hw->chip_id == CHIP_ID_YUKON_EC_U && + hw->chip_rev == CHIP_REV_YU_EC_U_A0) sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), ECU_TXFF_LEV); sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map, @@ -1907,8 +1907,8 @@ static int sky2_down(struct net_device *dev) sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); /* Workaround shared GMAC reset */ - if (!(hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0 - && port == 0 && hw->dev[1] && netif_running(hw->dev[1]))) + if (!(hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0 && + port == 0 && hw->dev[1] && netif_running(hw->dev[1]))) sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); @@ -2085,8 +2085,8 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) sky2->flow_status = FC_TX; } - if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000 - && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)) + if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000 && + !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)) sky2->flow_status = FC_NONE; if (sky2->flow_status & FC_TX) @@ -3244,8 +3244,8 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; - if ((wol->wolopts & ~sky2_wol_supported(sky2->hw)) - || !device_can_wakeup(&hw->pdev->dev)) + if ((wol->wolopts & ~sky2_wol_supported(sky2->hw)) || + !device_can_wakeup(&hw->pdev->dev)) return -EOPNOTSUPP; sky2->wol = wol->wolopts; diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 6640469b5d3..ba5bbc50344 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -956,8 +956,8 @@ static void slip_unesc(struct slip *sl, unsigned char s) clear_bit(SLF_KEEPTEST, &sl->flags); #endif - if (!test_and_clear_bit(SLF_ERROR, &sl->flags) - && (sl->rcount > 2)) + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && + (sl->rcount > 2)) sl_bump(sl); clear_bit(SLF_ESCAPE, &sl->flags); sl->rcount = 0; @@ -1039,8 +1039,8 @@ static void slip_unesc6(struct slip *sl, unsigned char s) clear_bit(SLF_KEEPTEST, &sl->flags); #endif - if (!test_and_clear_bit(SLF_ERROR, &sl->flags) - && (sl->rcount > 2)) + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && + (sl->rcount > 2)) sl_bump(sl); sl->rcount = 0; sl->xbits = 0; diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index c791ef76c1d..a93f122e9a9 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -268,9 +268,9 @@ static int __init ultramca_probe(struct device *gen_dev) } } - if(!tirq || !tbase - || (irq && irq != tirq) - || (base_addr && tbase != base_addr)) + if(!tirq || !tbase || + (irq && irq != tirq) || + (base_addr && tbase != base_addr)) /* FIXME: we're trying to force the ordering of the * devices here, there should be a way of getting this * to happen */ diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 0b56ab468d2..ae4983a5127 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -2283,7 +2283,7 @@ static int __devinit smc_drv_probe(struct platform_device *pdev) ndev->irq = ires->start; - if (ires->flags & IRQF_TRIGGER_MASK) + if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK) irq_flags = ires->flags & IRQF_TRIGGER_MASK; ret = smc_request_attrib(pdev, ndev); @@ -2365,9 +2365,10 @@ static int __devexit smc_drv_remove(struct platform_device *pdev) return 0; } -static int smc_drv_suspend(struct platform_device *dev, pm_message_t state) +static int smc_drv_suspend(struct device *dev) { - struct net_device *ndev = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); if (ndev) { if (netif_running(ndev)) { @@ -2379,9 +2380,10 @@ static int smc_drv_suspend(struct platform_device *dev, pm_message_t state) return 0; } -static int smc_drv_resume(struct platform_device *dev) +static int smc_drv_resume(struct device *dev) { - struct net_device *ndev = platform_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); if (ndev) { struct smc_local *lp = netdev_priv(ndev); @@ -2397,14 +2399,18 @@ static int smc_drv_resume(struct platform_device *dev) return 0; } +static struct dev_pm_ops smc_drv_pm_ops = { + .suspend = smc_drv_suspend, + .resume = smc_drv_resume, +}; + static struct platform_driver smc_driver = { .probe = smc_drv_probe, .remove = __devexit_p(smc_drv_remove), - .suspend = smc_drv_suspend, - .resume = smc_drv_resume, .driver = { .name = CARDNAME, .owner = THIS_MODULE, + .pm = &smc_drv_pm_ops, }, }; diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 3911be7c0cb..7815bfc300f 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -158,8 +158,8 @@ static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_outsb(a, r, p, l) writesb((a) + (r), p, (l)) #define SMC_IRQ_FLAGS (-1) /* from resource */ -#elif defined(CONFIG_MACH_LOGICPD_PXA270) \ - || defined(CONFIG_MACH_NOMADIK_8815NHK) +#elif defined(CONFIG_MACH_LOGICPD_PXA270) || \ + defined(CONFIG_MACH_NOMADIK_8815NHK) #define SMC_CAN_USE_8BIT 0 #define SMC_CAN_USE_16BIT 1 @@ -258,9 +258,9 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define RPC_LSA_DEFAULT RPC_LED_TX_RX #define RPC_LSB_DEFAULT RPC_LED_100_10 -#elif defined(CONFIG_MACH_LPD79520) \ - || defined(CONFIG_MACH_LPD7A400) \ - || defined(CONFIG_MACH_LPD7A404) +#elif defined(CONFIG_MACH_LPD79520) || \ + defined(CONFIG_MACH_LPD7A400) || \ + defined(CONFIG_MACH_LPD7A404) /* The LPD7X_IOBARRIER is necessary to overcome a mismatch between the * way that the CPU handles chip selects and the way that the SMC chip diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 7f01e60d517..4d0d5c56bed 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -748,8 +748,8 @@ static void smsc911x_phy_adjust_link(struct net_device *dev) * usage is 10/100 indicator */ pdata->gpio_setting = smsc911x_reg_read(pdata, GPIO_CFG); - if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) - && (!pdata->using_extphy)) { + if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) && + (!pdata->using_extphy)) { /* Force 10/100 LED off, after saving * orginal GPIO configuration */ pdata->gpio_orig_setting = pdata->gpio_setting; diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 92e2bbe6b49..12f0f5d74e3 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -252,6 +252,9 @@ static int smsc9420_ethtool_get_settings(struct net_device *dev, { struct smsc9420_pdata *pd = netdev_priv(dev); + if (!pd->phy_dev) + return -ENODEV; + cmd->maxtxpkt = 1; cmd->maxrxpkt = 1; return phy_ethtool_gset(pd->phy_dev, cmd); @@ -262,6 +265,9 @@ static int smsc9420_ethtool_set_settings(struct net_device *dev, { struct smsc9420_pdata *pd = netdev_priv(dev); + if (!pd->phy_dev) + return -ENODEV; + return phy_ethtool_sset(pd->phy_dev, cmd); } @@ -290,6 +296,10 @@ static void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data) static int smsc9420_ethtool_nway_reset(struct net_device *netdev) { struct smsc9420_pdata *pd = netdev_priv(netdev); + + if (!pd->phy_dev) + return -ENODEV; + return phy_start_aneg(pd->phy_dev); } @@ -312,6 +322,10 @@ smsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs, for (i = 0; i < 0x100; i += (sizeof(u32))) data[j++] = smsc9420_reg_read(pd, i); + // cannot read phy registers if the net device is down + if (!phy_dev) + return; + for (i = 0; i <= 31; i++) data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i); } diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index aa10158adb9..95db60adde4 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -1482,8 +1482,8 @@ static int __netdev_rx(struct net_device *dev, int *quota) printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d, quota %d.\n", pkt_len, *quota); /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + if (pkt_len < rx_copybreak && + (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(np->pci_dev, np->rx_info[entry].mapping, @@ -1793,8 +1793,8 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ rx_mode |= AcceptAll; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ rx_mode |= AcceptBroadcast|AcceptAllMulticast|PerfectFilter; } else if (dev->mc_count <= 14) { diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c index e961e7593c1..508fba8fa07 100644 --- a/drivers/net/stmmac/stmmac_main.c +++ b/drivers/net/stmmac/stmmac_main.c @@ -416,13 +416,8 @@ static void init_dma_desc_rings(struct net_device *dev) unsigned int txsize = priv->dma_tx_size; unsigned int rxsize = priv->dma_rx_size; unsigned int bfsize = priv->dma_buf_sz; - int buff2_needed = 0; - int dis_ic = 0; + int buff2_needed = 0, dis_ic = 0; -#ifdef CONFIG_STMMAC_TIMER - /* Using Timers disable interrupts on completion for the reception */ - dis_ic = 1; -#endif /* Set the Buffer size according to the MTU; * indeed, in case of jumbo we need to bump-up the buffer sizes. */ @@ -437,6 +432,11 @@ static void init_dma_desc_rings(struct net_device *dev) else bfsize = DMA_BUFFER_SIZE; +#ifdef CONFIG_STMMAC_TIMER + /* Disable interrupts on completion for the reception if timer is on */ + if (likely(priv->tm->enable)) + dis_ic = 1; +#endif /* If the MTU exceeds 8k so use the second buffer in the chain */ if (bfsize >= BUF_SIZE_8KiB) buff2_needed = 1; @@ -809,20 +809,22 @@ static void stmmac_tx(struct stmmac_priv *priv) static inline void stmmac_enable_irq(struct stmmac_priv *priv) { -#ifndef CONFIG_STMMAC_TIMER - writel(DMA_INTR_DEFAULT_MASK, priv->dev->base_addr + DMA_INTR_ENA); -#else - priv->tm->timer_start(tmrate); +#ifdef CONFIG_STMMAC_TIMER + if (likely(priv->tm->enable)) + priv->tm->timer_start(tmrate); + else #endif + writel(DMA_INTR_DEFAULT_MASK, priv->dev->base_addr + DMA_INTR_ENA); } static inline void stmmac_disable_irq(struct stmmac_priv *priv) { -#ifndef CONFIG_STMMAC_TIMER - writel(0, priv->dev->base_addr + DMA_INTR_ENA); -#else - priv->tm->timer_stop(); +#ifdef CONFIG_STMMAC_TIMER + if (likely(priv->tm->enable)) + priv->tm->timer_stop(); + else #endif + writel(0, priv->dev->base_addr + DMA_INTR_ENA); } static int stmmac_has_work(struct stmmac_priv *priv) @@ -920,8 +922,7 @@ static void stmmac_dma_interrupt(struct net_device *dev) DBG(intr, INFO, "CSR5[15] DMA ABNORMAL IRQ: "); if (unlikely(intr_status & DMA_STATUS_UNF)) { DBG(intr, INFO, "transmit underflow\n"); - if (unlikely(tc != SF_DMA_MODE) - && (tc <= 256)) { + if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) { /* Try to bump up the threshold */ tc += 64; priv->mac_type->ops->dma_mode(ioaddr, tc, @@ -1031,22 +1032,23 @@ static int stmmac_open(struct net_device *dev) } #ifdef CONFIG_STMMAC_TIMER - priv->tm = kmalloc(sizeof(struct stmmac_timer *), GFP_KERNEL); + priv->tm = kzalloc(sizeof(struct stmmac_timer *), GFP_KERNEL); if (unlikely(priv->tm == NULL)) { pr_err("%s: ERROR: timer memory alloc failed \n", __func__); return -ENOMEM; } priv->tm->freq = tmrate; - /* Test if the HW timer can be actually used. - * In case of failure continue with no timer. */ + /* Test if the external timer can be actually used. + * In case of failure continue without timer. */ if (unlikely((stmmac_open_ext_timer(dev, priv->tm)) < 0)) { - pr_warning("stmmaceth: cannot attach the HW timer\n"); + pr_warning("stmmaceth: cannot attach the external timer.\n"); tmrate = 0; priv->tm->freq = 0; priv->tm->timer_start = stmmac_no_timer_started; priv->tm->timer_stop = stmmac_no_timer_stopped; - } + } else + priv->tm->enable = 1; #endif /* Create and initialize the TX/RX descriptors chains. */ @@ -1322,9 +1324,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) /* Interrupt on completition only for the latest segment */ priv->mac_type->ops->close_tx_desc(desc); + #ifdef CONFIG_STMMAC_TIMER - /* Clean IC while using timers */ - priv->mac_type->ops->clear_tx_ic(desc); + /* Clean IC while using timer */ + if (likely(priv->tm->enable)) + priv->mac_type->ops->clear_tx_ic(desc); #endif /* To avoid raise condition */ priv->mac_type->ops->set_tx_owner(first); @@ -2028,7 +2032,8 @@ static int stmmac_suspend(struct platform_device *pdev, pm_message_t state) #ifdef CONFIG_STMMAC_TIMER priv->tm->timer_stop(); - dis_ic = 1; + if (likely(priv->tm->enable)) + dis_ic = 1; #endif napi_disable(&priv->napi); diff --git a/drivers/net/stmmac/stmmac_timer.c b/drivers/net/stmmac/stmmac_timer.c index b838c658207..679f61ffb1f 100644 --- a/drivers/net/stmmac/stmmac_timer.c +++ b/drivers/net/stmmac/stmmac_timer.c @@ -63,7 +63,7 @@ int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm) stmmac_rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); if (stmmac_rtc == NULL) { - pr_error("open rtc device failed\n"); + pr_err("open rtc device failed\n"); return -ENODEV; } @@ -71,7 +71,7 @@ int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm) /* Periodic mode is not supported */ if ((rtc_irq_set_freq(stmmac_rtc, &stmmac_task, tm->freq) < 0)) { - pr_error("set periodic failed\n"); + pr_err("set periodic failed\n"); rtc_irq_unregister(stmmac_rtc, &stmmac_task); rtc_class_close(stmmac_rtc); return -1; diff --git a/drivers/net/stmmac/stmmac_timer.h b/drivers/net/stmmac/stmmac_timer.h index f795cae3372..6863590d184 100644 --- a/drivers/net/stmmac/stmmac_timer.h +++ b/drivers/net/stmmac/stmmac_timer.h @@ -26,6 +26,7 @@ struct stmmac_timer { void (*timer_start) (unsigned int new_freq); void (*timer_stop) (void); unsigned int freq; + unsigned int enable; }; /* Open the HW timer device and return 0 in case of success */ diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 5c396c2e6e7..d58e1891ca6 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -603,8 +603,8 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, strcmp (media[card_idx], "4") == 0) { np->speed = 100; np->mii_if.full_duplex = 1; - } else if (strcmp (media[card_idx], "100mbps_hd") == 0 - || strcmp (media[card_idx], "3") == 0) { + } else if (strcmp (media[card_idx], "100mbps_hd") == 0 || + strcmp (media[card_idx], "3") == 0) { np->speed = 100; np->mii_if.full_duplex = 0; } else if (strcmp (media[card_idx], "10mbps_fd") == 0 || @@ -1079,8 +1079,8 @@ start_tx (struct sk_buff *skb, struct net_device *dev) tasklet_schedule(&np->tx_tasklet); /* On some architectures: explicitly flush cache lines here. */ - if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1 - && !netif_queue_stopped(dev)) { + if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1 && + !netif_queue_stopped(dev)) { /* do nothing */ } else { netif_stop_queue (dev); @@ -1336,8 +1336,8 @@ static void rx_poll(unsigned long data) #endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + if (pkt_len < rx_copybreak && + (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(np->pci_dev, le32_to_cpu(desc->frag[0].addr), @@ -1517,8 +1517,8 @@ static void set_rx_mode(struct net_device *dev) if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index f7a02917ce5..19905460def 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -1031,8 +1031,8 @@ struct gem { #endif }; -#define found_mii_phy(gp) ((gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) \ - && gp->phy_mii.def && gp->phy_mii.def->ops) +#define found_mii_phy(gp) ((gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) && \ + gp->phy_mii.def && gp->phy_mii.def->ops) #define ALIGNED_RX_SKB_ADDR(addr) \ ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr)) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 1f842a78acd..6762f1c6ec8 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -1226,10 +1226,16 @@ static void happy_meal_clean_rings(struct happy_meal *hp) for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { txd = &hp->happy_block->happy_meal_txd[i]; dma_addr = hme_read_desc32(hp, &txd->tx_addr); - dma_unmap_single(hp->dma_dev, dma_addr, - (hme_read_desc32(hp, &txd->tx_flags) - & TXFLAG_SIZE), - DMA_TO_DEVICE); + if (!frag) + dma_unmap_single(hp->dma_dev, dma_addr, + (hme_read_desc32(hp, &txd->tx_flags) + & TXFLAG_SIZE), + DMA_TO_DEVICE); + else + dma_unmap_page(hp->dma_dev, dma_addr, + (hme_read_desc32(hp, &txd->tx_flags) + & TXFLAG_SIZE), + DMA_TO_DEVICE); if (frag != skb_shinfo(skb)->nr_frags) i++; @@ -1953,7 +1959,10 @@ static void happy_meal_tx(struct happy_meal *hp) dma_len = hme_read_desc32(hp, &this->tx_flags); dma_len &= TXFLAG_SIZE; - dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE); + if (!frag) + dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE); + else + dma_unmap_page(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE); elem = NEXT_TX(elem); this = &txbase[elem]; @@ -3047,9 +3056,9 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, int len; if (qfe_slot != -1 && - (addr = of_get_property(dp, - "local-mac-address", &len)) != NULL - && len == 6) { + (addr = of_get_property(dp, "local-mac-address", &len)) + != NULL && + len == 6) { memcpy(dev->dev_addr, addr, 6); } else { memcpy(dev->dev_addr, idprom->id_ethaddr, 6); diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 2fbac31767f..80b404f2b93 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -1784,9 +1784,9 @@ static void bdx_tx_cleanup(struct bdx_priv *priv) } #endif - if (unlikely(netif_queue_stopped(priv->ndev) - && netif_carrier_ok(priv->ndev) - && (priv->tx_level >= BDX_MIN_TX_LEVEL))) { + if (unlikely(netif_queue_stopped(priv->ndev) && + netif_carrier_ok(priv->ndev) && + (priv->tx_level >= BDX_MIN_TX_LEVEL))) { DBG("%s: %s: TX Q WAKE level %d\n", BDX_DRV_NAME, priv->ndev->name, priv->tx_level); netif_wake_queue(priv->ndev); @@ -2273,8 +2273,8 @@ bdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal) (((tx_max_coal * BDX_TXF_DESC_SZ) + PCK_TH_MULT - 1) / PCK_TH_MULT); - if ((rx_coal > 0x7FFF) || (tx_coal > 0x7FFF) - || (rx_max_coal > 0xF) || (tx_max_coal > 0xF)) + if ((rx_coal > 0x7FFF) || (tx_coal > 0x7FFF) || + (rx_max_coal > 0xF) || (tx_max_coal > 0xF)) return -EINVAL; rdintcm = INT_REG_VAL(rx_coal, GET_INT_COAL_RC(priv->rdintcm), @@ -2347,8 +2347,8 @@ bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) tx_size = 3; /*Is there anything to do? */ - if ((rx_size == priv->rxf_size) - && (tx_size == priv->txd_size)) + if ((rx_size == priv->rxf_size) && + (tx_size == priv->txd_size)) return 0; priv->rxf_size = rx_size; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6e6db955b4a..3a74d216859 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -68,8 +68,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.104" -#define DRV_MODULE_RELDATE "November 13, 2009" +#define DRV_MODULE_VERSION "3.105" +#define DRV_MODULE_RELDATE "December 2, 2009" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -4351,13 +4351,13 @@ static void tg3_tx(struct tg3_napi *tnapi) struct netdev_queue *txq; int index = tnapi - tp->napi; - if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) index--; txq = netdev_get_tx_queue(tp->dev, index); while (sw_idx != hw_idx) { - struct tx_ring_info *ri = &tnapi->tx_buffers[sw_idx]; + struct ring_info *ri = &tnapi->tx_buffers[sw_idx]; struct sk_buff *skb = ri->skb; int i, tx_bug = 0; @@ -4366,7 +4366,10 @@ static void tg3_tx(struct tg3_napi *tnapi) return; } - skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); + pci_unmap_single(tp->pdev, + pci_unmap_addr(ri, mapping), + skb_headlen(skb), + PCI_DMA_TODEVICE); ri->skb = NULL; @@ -4376,6 +4379,11 @@ static void tg3_tx(struct tg3_napi *tnapi) ri = &tnapi->tx_buffers[sw_idx]; if (unlikely(ri->skb != NULL || sw_idx == hw_idx)) tx_bug = 1; + + pci_unmap_page(tp->pdev, + pci_unmap_addr(ri, mapping), + skb_shinfo(skb)->frags[i].size, + PCI_DMA_TODEVICE); sw_idx = NEXT_TX(sw_idx); } @@ -4613,13 +4621,12 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - ETH_FCS_LEN; - if (len > RX_COPY_THRESHOLD - && tp->rx_offset == NET_IP_ALIGN - /* rx_offset will likely not equal NET_IP_ALIGN - * if this is a 5701 card running in PCI-X mode - * [see tg3_get_invariants()] - */ - ) { + if (len > RX_COPY_THRESHOLD && + tp->rx_offset == NET_IP_ALIGN) { + /* rx_offset will likely not equal NET_IP_ALIGN + * if this is a 5701 card running in PCI-X mode + * [see tg3_get_invariants()] + */ int skb_size; skb_size = tg3_alloc_rx_skb(tp, tpr, opaque_key, @@ -5334,17 +5341,21 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, } else { /* New SKB is guaranteed to be linear. */ entry = *start; - ret = skb_dma_map(&tp->pdev->dev, new_skb, DMA_TO_DEVICE); - new_addr = skb_shinfo(new_skb)->dma_head; + new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, + PCI_DMA_TODEVICE); + /* Make sure the mapping succeeded */ + if (pci_dma_mapping_error(tp->pdev, new_addr)) { + ret = -1; + dev_kfree_skb(new_skb); + new_skb = NULL; /* Make sure new skb does not cross any 4G boundaries. * Drop the packet if it does. */ - if (ret || ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) && - tg3_4g_overflow_test(new_addr, new_skb->len))) { - if (!ret) - skb_dma_unmap(&tp->pdev->dev, new_skb, - DMA_TO_DEVICE); + } else if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) && + tg3_4g_overflow_test(new_addr, new_skb->len)) { + pci_unmap_single(tp->pdev, new_addr, new_skb->len, + PCI_DMA_TODEVICE); ret = -1; dev_kfree_skb(new_skb); new_skb = NULL; @@ -5358,15 +5369,28 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, /* Now clean up the sw ring entries. */ i = 0; while (entry != last_plus_one) { + int len; + if (i == 0) - tnapi->tx_buffers[entry].skb = new_skb; + len = skb_headlen(skb); else + len = skb_shinfo(skb)->frags[i-1].size; + + pci_unmap_single(tp->pdev, + pci_unmap_addr(&tnapi->tx_buffers[entry], + mapping), + len, PCI_DMA_TODEVICE); + if (i == 0) { + tnapi->tx_buffers[entry].skb = new_skb; + pci_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, + new_addr); + } else { tnapi->tx_buffers[entry].skb = NULL; + } entry = NEXT_TX(entry); i++; } - skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); dev_kfree_skb(skb); return ret; @@ -5403,14 +5427,15 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, { struct tg3 *tp = netdev_priv(dev); u32 len, entry, base_flags, mss; - struct skb_shared_info *sp; dma_addr_t mapping; struct tg3_napi *tnapi; struct netdev_queue *txq; + unsigned int i, last; + txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); tnapi = &tp->napi[skb_get_queue_mapping(skb)]; - if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) tnapi++; /* We are running in BH disabled context with netif_tx_lock @@ -5477,20 +5502,19 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, (vlan_tx_tag_get(skb) << 16)); #endif - if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) { + len = skb_headlen(skb); + + /* Queue skb data, a.k.a. the main skb fragment. */ + mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(tp->pdev, mapping)) { dev_kfree_skb(skb); goto out_unlock; } - sp = skb_shinfo(skb); - - mapping = sp->dma_head; - tnapi->tx_buffers[entry].skb = skb; + pci_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping); - len = skb_headlen(skb); - - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) && !mss && skb->len > ETH_DATA_LEN) base_flags |= TXD_FLAG_JMB_PKT; @@ -5501,15 +5525,21 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, /* Now loop through additional data fragments, and queue them. */ if (skb_shinfo(skb)->nr_frags > 0) { - unsigned int i, last; - last = skb_shinfo(skb)->nr_frags - 1; for (i = 0; i <= last; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = frag->size; - mapping = sp->dma_maps[i]; + mapping = pci_map_page(tp->pdev, + frag->page, + frag->page_offset, + len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(tp->pdev, mapping)) + goto dma_error; + tnapi->tx_buffers[entry].skb = NULL; + pci_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, + mapping); tg3_set_txd(tnapi, entry, mapping, len, base_flags, (i == last) | (mss << 1)); @@ -5532,6 +5562,27 @@ out_unlock: mmiowb(); return NETDEV_TX_OK; + +dma_error: + last = i; + entry = tnapi->tx_prod; + tnapi->tx_buffers[entry].skb = NULL; + pci_unmap_single(tp->pdev, + pci_unmap_addr(&tnapi->tx_buffers[entry], mapping), + skb_headlen(skb), + PCI_DMA_TODEVICE); + for (i = 0; i <= last; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + entry = NEXT_TX(entry); + + pci_unmap_page(tp->pdev, + pci_unmap_addr(&tnapi->tx_buffers[entry], + mapping), + frag->size, PCI_DMA_TODEVICE); + } + + dev_kfree_skb(skb); + return NETDEV_TX_OK; } static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *, @@ -5579,15 +5630,16 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, { struct tg3 *tp = netdev_priv(dev); u32 len, entry, base_flags, mss; - struct skb_shared_info *sp; int would_hit_hwbug; dma_addr_t mapping; struct tg3_napi *tnapi; struct netdev_queue *txq; + unsigned int i, last; + txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); tnapi = &tp->napi[skb_get_queue_mapping(skb)]; - if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) tnapi++; /* We are running in BH disabled context with netif_tx_lock @@ -5674,25 +5726,23 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, (vlan_tx_tag_get(skb) << 16)); #endif - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) && !mss && skb->len > ETH_DATA_LEN) base_flags |= TXD_FLAG_JMB_PKT; - if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) { + len = skb_headlen(skb); + + mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(tp->pdev, mapping)) { dev_kfree_skb(skb); goto out_unlock; } - sp = skb_shinfo(skb); - - mapping = sp->dma_head; - tnapi->tx_buffers[entry].skb = skb; + pci_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping); would_hit_hwbug = 0; - len = skb_headlen(skb); - if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) && len <= 8) would_hit_hwbug = 1; @@ -5714,16 +5764,21 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb, /* Now loop through additional data fragments, and queue them. */ if (skb_shinfo(skb)->nr_frags > 0) { - unsigned int i, last; - last = skb_shinfo(skb)->nr_frags - 1; for (i = 0; i <= last; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; len = frag->size; - mapping = sp->dma_maps[i]; + mapping = pci_map_page(tp->pdev, + frag->page, + frag->page_offset, + len, PCI_DMA_TODEVICE); tnapi->tx_buffers[entry].skb = NULL; + pci_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, + mapping); + if (pci_dma_mapping_error(tp->pdev, mapping)) + goto dma_error; if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) && len <= 8) @@ -5779,6 +5834,27 @@ out_unlock: mmiowb(); return NETDEV_TX_OK; + +dma_error: + last = i; + entry = tnapi->tx_prod; + tnapi->tx_buffers[entry].skb = NULL; + pci_unmap_single(tp->pdev, + pci_unmap_addr(&tnapi->tx_buffers[entry], mapping), + skb_headlen(skb), + PCI_DMA_TODEVICE); + for (i = 0; i <= last; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + entry = NEXT_TX(entry); + + pci_unmap_page(tp->pdev, + pci_unmap_addr(&tnapi->tx_buffers[entry], + mapping), + frag->size, PCI_DMA_TODEVICE); + } + + dev_kfree_skb(skb); + return NETDEV_TX_OK; } static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp, @@ -6046,8 +6122,9 @@ static void tg3_free_rings(struct tg3 *tp) continue; for (i = 0; i < TG3_TX_RING_SIZE; ) { - struct tx_ring_info *txp; + struct ring_info *txp; struct sk_buff *skb; + unsigned int k; txp = &tnapi->tx_buffers[i]; skb = txp->skb; @@ -6057,11 +6134,22 @@ static void tg3_free_rings(struct tg3 *tp) continue; } - skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); - + pci_unmap_single(tp->pdev, + pci_unmap_addr(txp, mapping), + skb_headlen(skb), + PCI_DMA_TODEVICE); txp->skb = NULL; - i += skb_shinfo(skb)->nr_frags + 1; + i++; + + for (k = 0; k < skb_shinfo(skb)->nr_frags; k++) { + txp = &tnapi->tx_buffers[i & (TG3_TX_RING_SIZE - 1)]; + pci_unmap_page(tp->pdev, + pci_unmap_addr(txp, mapping), + skb_shinfo(skb)->frags[k].size, + PCI_DMA_TODEVICE); + i++; + } dev_kfree_skb_any(skb); } @@ -6190,6 +6278,24 @@ static int tg3_alloc_consistent(struct tg3 *tp) memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); sblk = tnapi->hw_status; + /* If multivector TSS is enabled, vector 0 does not handle + * tx interrupts. Don't allocate any resources for it. + */ + if ((!i && !(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) || + (i && (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS))) { + tnapi->tx_buffers = kzalloc(sizeof(struct ring_info) * + TG3_TX_RING_SIZE, + GFP_KERNEL); + if (!tnapi->tx_buffers) + goto err_out; + + tnapi->tx_ring = pci_alloc_consistent(tp->pdev, + TG3_TX_RING_BYTES, + &tnapi->tx_desc_mapping); + if (!tnapi->tx_ring) + goto err_out; + } + /* * When RSS is enabled, the status block format changes * slightly. The "rx_jumbo_consumer", "reserved", @@ -6230,17 +6336,6 @@ static int tg3_alloc_consistent(struct tg3 *tp) goto err_out; memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); - - tnapi->tx_buffers = kzalloc(sizeof(struct tx_ring_info) * - TG3_TX_RING_SIZE, GFP_KERNEL); - if (!tnapi->tx_buffers) - goto err_out; - - tnapi->tx_ring = pci_alloc_consistent(tp->pdev, - TG3_TX_RING_BYTES, - &tnapi->tx_desc_mapping); - if (!tnapi->tx_ring) - goto err_out; } return 0; @@ -6876,7 +6971,8 @@ static int tg3_chip_reset(struct tg3 *tp) if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) { val = tr32(0x7c00); tw32(0x7c00, val | (1 << 25)); @@ -7228,19 +7324,21 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) { int i; - if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { + if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) { tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs); tw32(HOSTCC_TXMAX_FRAMES, ec->tx_max_coalesced_frames); tw32(HOSTCC_TXCOAL_MAXF_INT, ec->tx_max_coalesced_frames_irq); - - tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs); - tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames); - tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq); } else { tw32(HOSTCC_TXCOL_TICKS, 0); tw32(HOSTCC_TXMAX_FRAMES, 0); tw32(HOSTCC_TXCOAL_MAXF_INT, 0); + } + if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) { + tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs); + tw32(HOSTCC_RXMAX_FRAMES, ec->rx_max_coalesced_frames); + tw32(HOSTCC_RXCOAL_MAXF_INT, ec->rx_max_coalesced_frames_irq); + } else { tw32(HOSTCC_RXCOL_TICKS, 0); tw32(HOSTCC_RXMAX_FRAMES, 0); tw32(HOSTCC_RXCOAL_MAXF_INT, 0); @@ -7263,25 +7361,31 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec) reg = HOSTCC_RXCOL_TICKS_VEC1 + i * 0x18; tw32(reg, ec->rx_coalesce_usecs); - reg = HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18; - tw32(reg, ec->tx_coalesce_usecs); reg = HOSTCC_RXMAX_FRAMES_VEC1 + i * 0x18; tw32(reg, ec->rx_max_coalesced_frames); - reg = HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18; - tw32(reg, ec->tx_max_coalesced_frames); reg = HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18; tw32(reg, ec->rx_max_coalesced_frames_irq); - reg = HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18; - tw32(reg, ec->tx_max_coalesced_frames_irq); + + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) { + reg = HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18; + tw32(reg, ec->tx_coalesce_usecs); + reg = HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18; + tw32(reg, ec->tx_max_coalesced_frames); + reg = HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18; + tw32(reg, ec->tx_max_coalesced_frames_irq); + } } for (; i < tp->irq_max - 1; i++) { tw32(HOSTCC_RXCOL_TICKS_VEC1 + i * 0x18, 0); - tw32(HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18, 0); tw32(HOSTCC_RXMAX_FRAMES_VEC1 + i * 0x18, 0); - tw32(HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18, 0); tw32(HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); - tw32(HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); + + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) { + tw32(HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18, 0); + tw32(HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18, 0); + tw32(HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18, 0); + } } } @@ -7295,6 +7399,8 @@ static void tg3_rings_reset(struct tg3 *tp) /* Disable all transmit rings but the first. */ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16; + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) + limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2; else limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE; @@ -7309,7 +7415,8 @@ static void tg3_rings_reset(struct tg3 *tp) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17; else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 4; else limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE; @@ -7382,17 +7489,19 @@ static void tg3_rings_reset(struct tg3 *tp) /* Clear status block in ram. */ memset(tnapi->hw_status, 0, TG3_HW_STATUS_SIZE); - tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping, - (TG3_TX_RING_SIZE << - BDINFO_FLAGS_MAXLEN_SHIFT), - NIC_SRAM_TX_BUFFER_DESC); + if (tnapi->tx_ring) { + tg3_set_bdinfo(tp, txrcb, tnapi->tx_desc_mapping, + (TG3_TX_RING_SIZE << + BDINFO_FLAGS_MAXLEN_SHIFT), + NIC_SRAM_TX_BUFFER_DESC); + txrcb += TG3_BDINFO_SIZE; + } tg3_set_bdinfo(tp, rxrcb, tnapi->rx_rcb_mapping, (TG3_RX_RCB_RING_SIZE(tp) << BDINFO_FLAGS_MAXLEN_SHIFT), 0); stblk += 8; - txrcb += TG3_BDINFO_SIZE; rxrcb += TG3_BDINFO_SIZE; } } @@ -7504,7 +7613,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (err) return err; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) { val = tr32(TG3PCI_DMA_RW_CTRL) & ~DMA_RWCTRL_DIS_CACHE_ALIGNMENT; tw32(TG3PCI_DMA_RW_CTRL, val | tp->dma_rwctrl); @@ -7665,7 +7775,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) BDINFO_FLAGS_DISABLED); } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) val = (RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT) | (RX_STD_MAX_SIZE << 2); else @@ -7682,7 +7793,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tp->rx_jumbo_pending : 0; tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) { tw32(STD_REPLENISH_LWM, 32); tw32(JMB_REPLENISH_LWM, 16); } @@ -7935,7 +8047,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8); val = SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE; - if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX) + if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) val |= SNDBDI_MODE_MULTI_TXQ_EN; tw32(SNDBDI_MODE, val); tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE); @@ -8359,7 +8471,8 @@ static int tg3_test_interrupt(struct tg3 *tp) * Turn off MSI one shot mode. Otherwise this test has no * observable way to know whether the interrupt was delivered. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) && (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE; tw32(MSGINT_MODE, val); @@ -8402,7 +8515,8 @@ static int tg3_test_interrupt(struct tg3 *tp) if (intr_ok) { /* Reenable MSI one shot mode. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 && + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) && (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) { val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE; tw32(MSGINT_MODE, val); @@ -8543,7 +8657,11 @@ static bool tg3_enable_msix(struct tg3 *tp) for (i = 0; i < tp->irq_max; i++) tp->napi[i].irq_vec = msix_ent[i].vector; - tp->dev->real_num_tx_queues = tp->irq_cnt - 1; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS; + tp->dev->real_num_tx_queues = tp->irq_cnt - 1; + } else + tp->dev->real_num_tx_queues = 1; return true; } @@ -8694,6 +8812,7 @@ static int tg3_open(struct net_device *dev) } if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765 && (tp->tg3_flags2 & TG3_FLG2_USING_MSI) && (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)) { u32 val = tr32(PCIE_TRANSACTION_CFG); @@ -10637,7 +10756,8 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) for (i = 14; i < tx_len; i++) tx_data[i] = (u8) (i & 0xff); - if (skb_dma_map(&tp->pdev->dev, skb, DMA_TO_DEVICE)) { + map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(tp->pdev, map)) { dev_kfree_skb(skb); return -EIO; } @@ -10651,8 +10771,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) num_pkts = 0; - tg3_set_txd(tnapi, tnapi->tx_prod, - skb_shinfo(skb)->dma_head, tx_len, 0, 1); + tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, 0, 1); tnapi->tx_prod++; num_pkts++; @@ -10676,7 +10795,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) break; } - skb_dma_unmap(&tp->pdev->dev, skb, DMA_TO_DEVICE); + pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); if (tx_idx != tnapi->tx_prod) @@ -11588,7 +11707,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_5761_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tg3_get_5906_nvram_info(tp); - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tg3_get_57780_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) tg3_get_5717_nvram_info(tp); @@ -12313,7 +12433,7 @@ skip_phy_reset: static void __devinit tg3_read_partno(struct tg3 *tp) { - unsigned char vpd_data[256]; /* in little-endian format */ + unsigned char vpd_data[TG3_NVM_VPD_LEN]; /* in little-endian format */ unsigned int i; u32 magic; @@ -12322,48 +12442,37 @@ static void __devinit tg3_read_partno(struct tg3 *tp) goto out_not_found; if (magic == TG3_EEPROM_MAGIC) { - for (i = 0; i < 256; i += 4) { + for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) { u32 tmp; /* The data is in little-endian format in NVRAM. * Use the big-endian read routines to preserve * the byte order as it exists in NVRAM. */ - if (tg3_nvram_read_be32(tp, 0x100 + i, &tmp)) + if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &tmp)) goto out_not_found; memcpy(&vpd_data[i], &tmp, sizeof(tmp)); } } else { - int vpd_cap; - - vpd_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_VPD); - for (i = 0; i < 256; i += 4) { - u32 tmp, j = 0; - __le32 v; - u16 tmp16; - - pci_write_config_word(tp->pdev, vpd_cap + PCI_VPD_ADDR, - i); - while (j++ < 100) { - pci_read_config_word(tp->pdev, vpd_cap + - PCI_VPD_ADDR, &tmp16); - if (tmp16 & 0x8000) - break; - msleep(1); - } - if (!(tmp16 & 0x8000)) + ssize_t cnt; + unsigned int pos = 0, i = 0; + + for (; pos < TG3_NVM_VPD_LEN && i < 3; i++, pos += cnt) { + cnt = pci_read_vpd(tp->pdev, pos, + TG3_NVM_VPD_LEN - pos, + &vpd_data[pos]); + if (cnt == -ETIMEDOUT || -EINTR) + cnt = 0; + else if (cnt < 0) goto out_not_found; - - pci_read_config_dword(tp->pdev, vpd_cap + PCI_VPD_DATA, - &tmp); - v = cpu_to_le32(tmp); - memcpy(&vpd_data[i], &v, sizeof(v)); } + if (pos != TG3_NVM_VPD_LEN) + goto out_not_found; } /* Now parse and find the part number. */ - for (i = 0; i < 254; ) { + for (i = 0; i < TG3_NVM_VPD_LEN - 2; ) { unsigned char val = vpd_data[i]; unsigned int block_end; @@ -12382,7 +12491,7 @@ static void __devinit tg3_read_partno(struct tg3 *tp) (vpd_data[i + 2] << 8))); i += 3; - if (block_end > 256) + if (block_end > TG3_NVM_VPD_LEN) goto out_not_found; while (i < (block_end - 2)) { @@ -12391,7 +12500,8 @@ static void __devinit tg3_read_partno(struct tg3 *tp) int partno_len = vpd_data[i + 2]; i += 3; - if (partno_len > 24 || (partno_len + i) > 256) + if (partno_len > TG3_BPN_SIZE || + (partno_len + i) > TG3_NVM_VPD_LEN) goto out_not_found; memcpy(tp->board_part_number, @@ -12422,6 +12532,8 @@ out_not_found: else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 && tp->pdev->device == TG3PCI_DEVICE_TIGON3_57788) strcpy(tp->board_part_number, "BCM57788"); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) + strcpy(tp->board_part_number, "BCM57765"); else strcpy(tp->board_part_number, "none"); } @@ -12711,6 +12823,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_read_config_dword(tp->pdev, TG3PCI_GEN2_PRODID_ASICREV, &prod_id_asic_rev); + else if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_57781 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57785 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57761 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57765 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57791 || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57795) + pci_read_config_dword(tp->pdev, + TG3PCI_GEN15_PRODID_ASICREV, + &prod_id_asic_rev); else pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV, &prod_id_asic_rev); @@ -12864,7 +12985,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tp->tg3_flags3 |= TG3_FLG3_5755_PLUS; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || @@ -12891,7 +13013,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } /* Determine TSO capabilities */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tp->tg3_flags2 |= TG3_FLG2_HW_TSO_3; else if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) @@ -12927,7 +13050,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) { tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX; tp->irq_max = TG3_IRQ_MAX_VECS; } @@ -12941,9 +13065,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG; } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) + tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG; + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + (tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG)) tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE; pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, @@ -13136,7 +13264,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; /* Set up tp->grc_local_ctrl before calling tg3_set_power_state(). @@ -13215,7 +13344,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) !(tp->tg3_flags3 & TG3_FLG3_PHY_IS_FET) && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || @@ -13539,7 +13669,8 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val) #endif #endif - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) { val = goal ? 0 : DMA_RWCTRL_DIS_CACHE_ALIGNMENT; goto out; } @@ -13751,7 +13882,8 @@ static int __devinit tg3_test_dma(struct tg3 *tp) tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) goto out; if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { @@ -13944,7 +14076,8 @@ static void __devinit tg3_init_link_config(struct tg3 *tp) static void __devinit tg3_init_bufmgr_config(struct tg3 *tp) { if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) { tp->bufmgr_config.mbuf_read_dma_low_water = DEFAULT_MB_RDMA_LOW_WATER_5705; tp->bufmgr_config.mbuf_mac_rx_low_water = @@ -14349,7 +14482,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, if (err) { printk(KERN_ERR PFX "Could not obtain valid ethernet address, " "aborting.\n"); - goto err_out_fw; + goto err_out_iounmap; } if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { @@ -14358,7 +14491,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, printk(KERN_ERR PFX "Cannot map APE registers, " "aborting.\n"); err = -ENOMEM; - goto err_out_fw; + goto err_out_iounmap; } tg3_ape_lock_init(tp); @@ -14489,10 +14622,6 @@ err_out_apeunmap: tp->aperegs = NULL; } -err_out_fw: - if (tp->fw) - release_firmware(tp->fw); - err_out_iounmap: if (tp->regs) { iounmap(tp->regs); diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 453a34fb72b..cd30889650f 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -49,6 +49,12 @@ #define TG3PCI_DEVICE_TIGON3_5717 0x1655 #define TG3PCI_DEVICE_TIGON3_5718 0x1656 #define TG3PCI_DEVICE_TIGON3_5724 0x165c +#define TG3PCI_DEVICE_TIGON3_57781 0x16b1 +#define TG3PCI_DEVICE_TIGON3_57785 0x16b5 +#define TG3PCI_DEVICE_TIGON3_57761 0x16b0 +#define TG3PCI_DEVICE_TIGON3_57765 0x16b4 +#define TG3PCI_DEVICE_TIGON3_57791 0x16b2 +#define TG3PCI_DEVICE_TIGON3_57795 0x16b6 /* 0x04 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ @@ -122,6 +128,7 @@ #define ASIC_REV_5785 0x5785 #define ASIC_REV_57780 0x57780 #define ASIC_REV_5717 0x5717 +#define ASIC_REV_57765 0x57785 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -220,6 +227,7 @@ /* 0xc0 --> 0xf4 unused */ #define TG3PCI_GEN2_PRODID_ASICREV 0x000000f4 +#define TG3PCI_GEN15_PRODID_ASICREV 0x000000fc /* 0xf8 --> 0x200 unused */ #define TG3_CORR_ERR_STAT 0x00000110 @@ -1813,6 +1821,11 @@ #define TG3_OTP_DEFAULT 0x286c1640 + +/* Hardware Legacy NVRAM layout */ +#define TG3_NVM_VPD_OFF 0x100 +#define TG3_NVM_VPD_LEN 256 + /* Hardware Selfboot NVRAM layout */ #define TG3_NVM_HWSB_CFG1 0x00000004 #define TG3_NVM_HWSB_CFG1_MAJMSK 0xf8000000 @@ -2441,10 +2454,6 @@ struct ring_info { DECLARE_PCI_UNMAP_ADDR(mapping) }; -struct tx_ring_info { - struct sk_buff *skb; -}; - struct tg3_config_info { u32 flags; }; @@ -2608,7 +2617,7 @@ struct tg3_napi { struct tg3_rx_buffer_desc *rx_rcb; struct tg3_tx_buffer_desc *tx_ring; - struct tx_ring_info *tx_buffers; + struct ring_info *tx_buffers; dma_addr_t status_mapping; dma_addr_t rx_rcb_mapping; @@ -2795,9 +2804,11 @@ struct tg3 { #define TG3_FLG3_NO_NVRAM 0x00004000 #define TG3_FLG3_PHY_IS_FET 0x00010000 #define TG3_FLG3_ENABLE_RSS 0x00020000 +#define TG3_FLG3_ENABLE_TSS 0x00040000 #define TG3_FLG3_4G_DMA_BNDRY_BUG 0x00080000 #define TG3_FLG3_40BIT_DMA_LIMIT_BUG 0x00100000 #define TG3_FLG3_SHORT_DMA_BUG 0x00200000 +#define TG3_FLG3_USE_JUMBO_BDFLAG 0x00400000 struct timer_list timer; u16 timer_counter; @@ -2887,8 +2898,9 @@ struct tg3 { u32 led_ctrl; u32 phy_otp; - char board_part_number[24]; -#define TG3_VER_SIZE 32 +#define TG3_BPN_SIZE 24 + char board_part_number[TG3_BPN_SIZE]; +#define TG3_VER_SIZE ETHTOOL_FWVERS_LEN char fw_ver[TG3_VER_SIZE]; u32 nic_sram_data_cfg; u32 pci_clock_ctrl; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 16f23f84920..fabaeffb315 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -1755,8 +1755,8 @@ static u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int ) ! ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { tlphy_ctl |= TLAN_TC_SWAPOL; TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); - } else if ( ( tlphy_sts & TLAN_TS_POLOK ) - && ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { + } else if ( ( tlphy_sts & TLAN_TS_POLOK ) && + ( tlphy_ctl & TLAN_TC_SWAPOL ) ) { tlphy_ctl &= ~TLAN_TC_SWAPOL; TLan_MiiWriteReg( dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); } diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 7b1fe9412b6..d6ccd59c7d0 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -712,8 +712,8 @@ static int streamer_open(struct net_device *dev) strcat(open_error, " - "); strcat(open_error, open_min_error[(error_code & 0x0f)]); - if (!streamer_priv->streamer_ring_speed - && ((error_code & 0x0f) == 0x0d)) + if (!streamer_priv->streamer_ring_speed && + ((error_code & 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); @@ -1032,8 +1032,8 @@ static irqreturn_t streamer_interrupt(int irq, void *dev_id) sisr = readw(streamer_mmio + SISR); while((sisr & (SISR_MI | SISR_SRB_REPLY | SISR_ADAPTER_CHECK | SISR_ASB_FREE | - SISR_ARB_CMD | SISR_TRB_REPLY | SISR_PAR_ERR | SISR_SERR_ERR)) - && (max_intr > 0)) { + SISR_ARB_CMD | SISR_TRB_REPLY | SISR_PAR_ERR | SISR_SERR_ERR)) && + (max_intr > 0)) { if(sisr & SISR_PAR_ERR) { writew(~SISR_PAR_ERR, streamer_mmio + SISR_RUM); diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index ebda61bc4c2..427a8970b6f 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -2309,9 +2309,9 @@ static irqreturn_t smctr_interrupt(int irq, void *dev_id) else { if((tp->acb_head->cmd - == ACB_CMD_READ_TRC_STATUS) - && (tp->acb_head->subcmd - == RW_TRC_STATUS_BLOCK)) + == ACB_CMD_READ_TRC_STATUS) && + (tp->acb_head->subcmd + == RW_TRC_STATUS_BLOCK)) { if(tp->ptr_bcn_type) { @@ -2331,8 +2331,8 @@ static irqreturn_t smctr_interrupt(int irq, void *dev_id) smctr_disable_16bit(dev); err = smctr_ring_status_chg(dev); smctr_enable_16bit(dev); - if((tp->ring_status & REMOVE_RECEIVED) - && (tp->config_word0 & NO_AUTOREMOVE)) + if((tp->ring_status & REMOVE_RECEIVED) && + (tp->config_word0 & NO_AUTOREMOVE)) { smctr_issue_remove_cmd(dev); } @@ -2511,9 +2511,9 @@ static int smctr_issue_init_timers_cmd(struct net_device *dev) tp->config_word0 = THDREN | DMA_TRIGGER | USETPT | NO_AUTOREMOVE; tp->config_word1 = 0; - if((tp->media_type == MEDIA_STP_16) - || (tp->media_type == MEDIA_UTP_16) - || (tp->media_type == MEDIA_STP_16_UTP_16)) + if((tp->media_type == MEDIA_STP_16) || + (tp->media_type == MEDIA_UTP_16) || + (tp->media_type == MEDIA_STP_16_UTP_16)) { tp->config_word0 |= FREQ_16MB_BIT; } @@ -2556,9 +2556,9 @@ static int smctr_issue_init_timers_cmd(struct net_device *dev) tp->config_word1 &= ~SOURCE_ROUTING_SPANNING_BITS; } - if((tp->media_type == MEDIA_STP_16) - || (tp->media_type == MEDIA_UTP_16) - || (tp->media_type == MEDIA_STP_16_UTP_16)) + if((tp->media_type == MEDIA_STP_16) || + (tp->media_type == MEDIA_UTP_16) || + (tp->media_type == MEDIA_STP_16_UTP_16)) { tp->config_word1 |= INTERFRAME_SPACING_16; } @@ -2568,9 +2568,9 @@ static int smctr_issue_init_timers_cmd(struct net_device *dev) *pTimer_Struc++ = tp->config_word0; *pTimer_Struc++ = tp->config_word1; - if((tp->media_type == MEDIA_STP_4) - || (tp->media_type == MEDIA_UTP_4) - || (tp->media_type == MEDIA_STP_4_UTP_4)) + if((tp->media_type == MEDIA_STP_4) || + (tp->media_type == MEDIA_UTP_4) || + (tp->media_type == MEDIA_STP_4_UTP_4)) { *pTimer_Struc++ = 0x00FA; /* prescale */ *pTimer_Struc++ = 0x2710; /* TPT_limit */ @@ -2990,8 +2990,8 @@ static int smctr_load_firmware(struct net_device *dev) } /* Verify the firmware exists and is there in the right amount. */ - if (!fw->data - || (*(fw->data + UCODE_VERSION_OFFSET) < UCODE_VERSION)) + if (!fw->data || + (*(fw->data + UCODE_VERSION_OFFSET) < UCODE_VERSION)) { err = (UCODE_NOT_PRESENT); goto out; @@ -3010,9 +3010,8 @@ static int smctr_load_firmware(struct net_device *dev) smctr_enable_16bit(dev); smctr_set_page(dev, (__u8 *)tp->ram_access); - if((smctr_checksum_firmware(dev)) - || (*(fw->data + UCODE_VERSION_OFFSET) - > tp->microcode_version)) + if((smctr_checksum_firmware(dev)) || + (*(fw->data + UCODE_VERSION_OFFSET) > tp->microcode_version)) { smctr_enable_adapter_ctrl_store(dev); @@ -3117,9 +3116,9 @@ static int smctr_lobe_media_test(struct net_device *dev) } /* Check if any frames received during test. */ - if((tp->rx_fcb_curr[MAC_QUEUE]->frame_status) - || (tp->rx_fcb_curr[NON_MAC_QUEUE]->frame_status)) - goto err; + if((tp->rx_fcb_curr[MAC_QUEUE]->frame_status) || + (tp->rx_fcb_curr[NON_MAC_QUEUE]->frame_status)) + goto err; /* Set receive mask to "Promisc" mode. */ tp->receive_mask = saved_rcv_mask; @@ -3303,8 +3302,8 @@ static int smctr_make_group_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv) /* Set Group Address Sub-vector to all zeros if only the * Group Address/Functional Address Indicator is set. */ - if(tsv->svv[0] == 0x80 && tsv->svv[1] == 0x00 - && tsv->svv[2] == 0x00 && tsv->svv[3] == 0x00) + if(tsv->svv[0] == 0x80 && tsv->svv[1] == 0x00 && + tsv->svv[2] == 0x00 && tsv->svv[3] == 0x00) tsv->svv[0] = 0x00; return (0); @@ -3876,10 +3875,10 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, /* NOTE: UNKNOWN MAC frames will NOT be passed up unless * ACCEPT_ATT_MAC_FRAMES is set. */ - if(((tp->receive_mask & ACCEPT_ATT_MAC_FRAMES) - && (xframe == (__u8)0)) - || ((tp->receive_mask & ACCEPT_EXT_MAC_FRAMES) - && (xframe == (__u8)1))) + if(((tp->receive_mask & ACCEPT_ATT_MAC_FRAMES) && + (xframe == (__u8)0)) || + ((tp->receive_mask & ACCEPT_EXT_MAC_FRAMES) && + (xframe == (__u8)1))) { rmf->vl = SWAP_BYTES(rmf->vl); @@ -3934,8 +3933,8 @@ static int smctr_ram_memory_test(struct net_device *dev) word_pattern = start_pattern; - for(j = 1; j < (__u32)(tp->ram_usable * 1024) - 1 - && (~err); j += 2, word_pattern++) + for(j = 1; j < (__u32)(tp->ram_usable * 1024) - 1 && (~err); + j += 2, word_pattern++) { word_read = *(__u16 *)(pword + j); if(word_read != word_pattern) @@ -3959,8 +3958,7 @@ static int smctr_ram_memory_test(struct net_device *dev) for(j = 0; j < (__u32)tp->ram_usable * 1024; j +=2) *(__u16 *)(pword + j) = word_pattern; - for(j =0; j < (__u32)tp->ram_usable * 1024 - && (~err); j += 2) + for(j =0; j < (__u32)tp->ram_usable * 1024 && (~err); j += 2) { word_read = *(__u16 *)(pword + j); if(word_read != word_pattern) @@ -4325,8 +4323,8 @@ static int smctr_restart_tx_chain(struct net_device *dev, short queue) if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_restart_tx_chain\n", dev->name); - if(tp->num_tx_fcbs_used[queue] != 0 - && tp->tx_queue_status[queue] == NOT_TRANSMITING) + if(tp->num_tx_fcbs_used[queue] != 0 && + tp->tx_queue_status[queue] == NOT_TRANSMITING) { tp->tx_queue_status[queue] = TRANSMITING; err = smctr_issue_resume_tx_fcb_cmd(dev, queue); @@ -4349,8 +4347,8 @@ static int smctr_ring_status_chg(struct net_device *dev) */ if(tp->ring_status_flags == MONITOR_STATE_CHANGED) { - if((tp->monitor_state == MS_ACTIVE_MONITOR_STATE) - || (tp->monitor_state == MS_STANDBY_MONITOR_STATE)) + if((tp->monitor_state == MS_ACTIVE_MONITOR_STATE) || + (tp->monitor_state == MS_STANDBY_MONITOR_STATE)) { tp->monitor_state_ready = 1; } @@ -4363,8 +4361,8 @@ static int smctr_ring_status_chg(struct net_device *dev) tp->monitor_state_ready = 0; /* Ring speed problem, switching to auto mode. */ - if(tp->monitor_state == MS_MONITOR_FSM_INACTIVE - && !tp->cleanup) + if(tp->monitor_state == MS_MONITOR_FSM_INACTIVE && + !tp->cleanup) { printk(KERN_INFO "%s: Incorrect ring speed switching.\n", dev->name); @@ -4442,8 +4440,8 @@ static int smctr_rx_frame(struct net_device *dev) { err = HARDWARE_FAILED; - if(((status & 0x007f) == 0) - || ((tp->receive_mask & ACCEPT_ERR_PACKETS) != 0)) + if(((status & 0x007f) == 0) || + ((tp->receive_mask & ACCEPT_ERR_PACKETS) != 0)) { /* frame length less the CRC (4 bytes) + FS (1 byte) */ rx_size = tp->rx_fcb_curr[queue]->frame_length - 5; @@ -4538,8 +4536,8 @@ static int smctr_send_dat(struct net_device *dev) } /* Check if GOOD frame Tx'ed. */ - if(!(fcb->frame_status & FCB_COMMAND_DONE) - || fcb->frame_status & (FCB_TX_STATUS_E | FCB_TX_AC_BITS)) + if(!(fcb->frame_status & FCB_COMMAND_DONE) || + fcb->frame_status & (FCB_TX_STATUS_E | FCB_TX_AC_BITS)) { return (INITIALIZE_FAILED); } @@ -4653,8 +4651,8 @@ static int smctr_send_lobe_media_test(struct net_device *dev) } /* Check if GOOD frame Tx'ed */ - if(!(fcb->frame_status & FCB_COMMAND_DONE) - || fcb->frame_status & (FCB_TX_STATUS_E | FCB_TX_AC_BITS)) + if(!(fcb->frame_status & FCB_COMMAND_DONE) || + fcb->frame_status & (FCB_TX_STATUS_E | FCB_TX_AC_BITS)) { return (LOBE_MEDIA_TEST_FAILED); } diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index fa152144aac..e3c42f5ac4a 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -729,8 +729,8 @@ static void tms380tr_timer_chk(unsigned long data) return; tms380tr_chk_outstanding_cmds(dev); - if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies) - && (tp->TplFree != tp->TplBusy)) + if(time_before(tp->LastSendTime + SEND_TIMEOUT, jiffies) && + (tp->TplFree != tp->TplBusy)) { /* Anything to send, but stalled too long */ tp->LastSendTime = jiffies; @@ -830,8 +830,8 @@ irqreturn_t tms380tr_interrupt(int irq, void *dev_id) } /* Reset system interrupt if not already done. */ - if(irq_type != STS_IRQ_TRANSMIT_STATUS - && irq_type != STS_IRQ_RECEIVE_STATUS) { + if(irq_type != STS_IRQ_TRANSMIT_STATUS && + irq_type != STS_IRQ_RECEIVE_STATUS) { tms380tr_reset_interrupt(dev); } @@ -895,10 +895,10 @@ static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqTy /* Check if this interrupt does use the SSB. */ - if(IrqType != STS_IRQ_TRANSMIT_STATUS - && IrqType != STS_IRQ_RECEIVE_STATUS - && IrqType != STS_IRQ_COMMAND_STATUS - && IrqType != STS_IRQ_RING_STATUS) + if(IrqType != STS_IRQ_TRANSMIT_STATUS && + IrqType != STS_IRQ_RECEIVE_STATUS && + IrqType != STS_IRQ_COMMAND_STATUS && + IrqType != STS_IRQ_RING_STATUS) { return (1); /* SSB not involved. */ } @@ -1485,8 +1485,8 @@ static int tms380tr_init_adapter(struct net_device *dev) /* Mask interesting status bits */ Status = SIFREADW(SIFSTS); Status &= STS_MASK; - } while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0) - && ((Status & STS_ERROR) == 0) && (loop_cnt != 0)); + } while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0) && + ((Status & STS_ERROR) == 0) && (loop_cnt != 0)); if((Status & (STS_INITIALIZE | STS_ERROR | STS_TEST)) == 0) { @@ -2183,8 +2183,8 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) } } - if(skb && (rpl->SkbStat == SKB_DATA_COPY - || rpl->SkbStat == SKB_DMA_DIRECT)) + if(skb && (rpl->SkbStat == SKB_DATA_COPY || + rpl->SkbStat == SKB_DMA_DIRECT)) { if(rpl->SkbStat == SKB_DATA_COPY) skb_copy_to_linear_data(skb, ReceiveDataPtr, diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c index db7d5e11855..9f6742fad6c 100644 --- a/drivers/net/tulip/21142.c +++ b/drivers/net/tulip/21142.c @@ -209,10 +209,10 @@ void t21142_lnk_change(struct net_device *dev, int csr5) printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n", dev->name, tp->csr6, ioread32(ioaddr + CSR6), ioread32(ioaddr + CSR12)); - } else if ((tp->nwayset && (csr5 & 0x08000000) - && (dev->if_port == 3 || dev->if_port == 5) - && (csr12 & 2) == 2) || - (tp->nway && (csr5 & (TPLnkFail)))) { + } else if ((tp->nwayset && (csr5 & 0x08000000) && + (dev->if_port == 3 || dev->if_port == 5) && + (csr12 & 2) == 2) || + (tp->nway && (csr5 & (TPLnkFail)))) { /* Link blew? Maybe restart NWay. */ del_timer_sync(&tp->timer); t21142_start_nway(dev); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 74e5ba42d38..d4255d44cb7 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -62,9 +62,9 @@ module_param (debug, int, 0); MODULE_PARM_DESC (debug, "de2104x bitmapped message enable number"); /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ -#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(CONFIG_SPARC) || defined(__ia64__) \ - || defined(__sh__) || defined(__mips__) +#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) || \ + defined(CONFIG_SPARC) || defined(__ia64__) || \ + defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else static int rx_copybreak = 100; diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 391acd32a6a..889f57aae89 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -174,10 +174,10 @@ void __devinit tulip_parse_eeprom(struct net_device *dev) } /* Do a fix-up based on the vendor half of the station address prefix. */ for (i = 0; eeprom_fixups[i].name; i++) { - if (dev->dev_addr[0] == eeprom_fixups[i].addr0 - && dev->dev_addr[1] == eeprom_fixups[i].addr1 - && dev->dev_addr[2] == eeprom_fixups[i].addr2) { - if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) + if (dev->dev_addr[0] == eeprom_fixups[i].addr0 && + dev->dev_addr[1] == eeprom_fixups[i].addr1 && + dev->dev_addr[2] == eeprom_fixups[i].addr2) { + if (dev->dev_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) i++; /* An Accton EN1207, not an outlaw Maxtech. */ memcpy(ee_data + 26, eeprom_fixups[i].newtable, sizeof(eeprom_fixups[i].newtable)); diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index c8d220cf2cc..2e8e8ee893c 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -170,8 +170,8 @@ int tulip_poll(struct napi_struct *napi, int budget) RxDescCollisionSeen | RxDescRunt | RxDescDescErr | - RxWholePkt)) != RxWholePkt - || pkt_len > 1518) { + RxWholePkt)) != RxWholePkt || + pkt_len > 1518) { if ((status & (RxLengthOver2047 | RxWholePkt)) != RxWholePkt) { /* Ingore earlier buffers. */ @@ -201,8 +201,8 @@ int tulip_poll(struct napi_struct *napi, int budget) /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < tulip_rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + if (pkt_len < tulip_rx_copybreak && + (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(tp->pdev, tp->rx_buffers[entry].mapping, @@ -395,8 +395,8 @@ static int tulip_rx(struct net_device *dev) RxDescCollisionSeen | RxDescRunt | RxDescDescErr | - RxWholePkt)) != RxWholePkt - || pkt_len > 1518) { + RxWholePkt)) != RxWholePkt || + pkt_len > 1518) { if ((status & (RxLengthOver2047 | RxWholePkt)) != RxWholePkt) { /* Ingore earlier buffers. */ @@ -425,8 +425,8 @@ static int tulip_rx(struct net_device *dev) /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < tulip_rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + if (pkt_len < tulip_rx_copybreak && + (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(tp->pdev, tp->rx_buffers[entry].mapping, diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index daddfa51853..d8fda83705b 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -468,8 +468,8 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx) int phy = phyn & 0x1f; int mii_status = tulip_mdio_read (dev, phy, MII_BMSR); if ((mii_status & 0x8301) == 0x8001 || - ((mii_status & BMSR_100BASE4) == 0 - && (mii_status & 0x7800) != 0)) { + ((mii_status & BMSR_100BASE4) == 0 && + (mii_status & 0x7800) != 0)) { /* preserve Becker logic, gain indentation level */ } else { continue; diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c index f49579128fb..d8418694bf4 100644 --- a/drivers/net/tulip/pnic2.c +++ b/drivers/net/tulip/pnic2.c @@ -316,9 +316,9 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) } } - if ((tp->nwayset && (csr5 & 0x08000000) - && (dev->if_port == 3 || dev->if_port == 5) - && (csr12 & 2) == 2) || (tp->nway && (csr5 & (TPLnkFail)))) { + if ((tp->nwayset && (csr5 & 0x08000000) && + (dev->if_port == 3 || dev->if_port == 5) && + (csr12 & 2) == 2) || (tp->nway && (csr5 & (TPLnkFail)))) { /* Link blew? Maybe restart NWay. */ diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 0df983bc03a..0fa3140d65b 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -64,9 +64,9 @@ const char * const medianame[32] = { }; /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ -#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(CONFIG_SPARC) || defined(__ia64__) \ - || defined(__sh__) || defined(__mips__) +#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) || \ + defined(CONFIG_SPARC) || defined(__ia64__) || \ + defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else static int rx_copybreak = 100; @@ -449,8 +449,8 @@ media_picked: iowrite32(0x0201B078, ioaddr + 0xB8); next_tick = 1*HZ; } - } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) - && ! tp->medialock) { + } else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) && + ! tp->medialock) { dev->if_port = 0; tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0); iowrite32(0x0f370000 | ioread16(ioaddr + 0x80), ioaddr + 0x80); @@ -535,9 +535,9 @@ static void tulip_tx_timeout(struct net_device *dev) if (tulip_debug > 1) printk(KERN_WARNING "%s: Transmit timeout using MII device.\n", dev->name); - } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 - || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881 - || tp->chip_id == DM910X) { + } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 || + tp->chip_id == MX98713 || tp->chip_id == COMPEX9881 || + tp->chip_id == DM910X) { printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12), @@ -1538,8 +1538,10 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, } } /* Lite-On boards have the address byte-swapped. */ - if ((dev->dev_addr[0] == 0xA0 || dev->dev_addr[0] == 0xC0 || dev->dev_addr[0] == 0x02) - && dev->dev_addr[1] == 0x00) + if ((dev->dev_addr[0] == 0xA0 || + dev->dev_addr[0] == 0xC0 || + dev->dev_addr[0] == 0x02) && + dev->dev_addr[1] == 0x00) for (i = 0; i < 6; i+=2) { char tmp = dev->dev_addr[i]; dev->dev_addr[i] = dev->dev_addr[i+1]; diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 1a52729c946..869a7a0005f 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1230,8 +1230,8 @@ static int netdev_rx(struct net_device *dev) #endif /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + if (pkt_len < rx_copybreak && + (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, @@ -1357,8 +1357,8 @@ static u32 __set_rx_mode(struct net_device *dev) memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = RxAcceptBroadcast | AcceptMulticast | RxAcceptAllPhys | AcceptMyPhys; - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ memset(mc_filter, 0xff, sizeof(mc_filter)); rx_mode = RxAcceptBroadcast | AcceptMulticast | AcceptMyPhys; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 079a97000e5..39f1fc650be 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1769,8 +1769,8 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * read csum_bits = rx->rxStatus & (TYPHOON_RX_IP_CHK_GOOD | TYPHOON_RX_UDP_CHK_GOOD | TYPHOON_RX_TCP_CHK_GOOD); if(csum_bits == - (TYPHOON_RX_IP_CHK_GOOD | TYPHOON_RX_TCP_CHK_GOOD) - || csum_bits == + (TYPHOON_RX_IP_CHK_GOOD | TYPHOON_RX_TCP_CHK_GOOD) || + csum_bits == (TYPHOON_RX_IP_CHK_GOOD | TYPHOON_RX_UDP_CHK_GOOD)) { new_skb->ip_summed = CHECKSUM_UNNECESSARY; } else diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 4469f2451a6..9f44c99777a 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -1306,8 +1306,8 @@ static int init_max_rx_buff_len(u16 max_rx_buf_len, u16 __iomem *mrblr_register) { /* max_rx_buf_len value must be a multiple of 128 */ - if ((max_rx_buf_len == 0) - || (max_rx_buf_len % UCC_GETH_MRBLR_ALIGNMENT)) + if ((max_rx_buf_len == 0) || + (max_rx_buf_len % UCC_GETH_MRBLR_ALIGNMENT)) return -EINVAL; out_be16(mrblr_register, max_rx_buf_len); @@ -2159,8 +2159,8 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) } if ((ug_info->numStationAddresses != - UCC_GETH_NUM_OF_STATION_ADDRESSES_1) - && ug_info->rxExtendedFiltering) { + UCC_GETH_NUM_OF_STATION_ADDRESSES_1) && + ug_info->rxExtendedFiltering) { if (netif_msg_probe(ugeth)) ugeth_err("%s: Number of station addresses greater than 1 " "not allowed in extended parsing mode.", @@ -2284,9 +2284,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) UCC_GETH_NUM_OF_STATION_ADDRESSES_1); ugeth->rx_extended_features = ugeth->rx_non_dynamic_extended_features || - (ug_info->vlanOperationTagged != UCC_GETH_VLAN_OPERATION_TAGGED_NOP) - || (ug_info->vlanOperationNonTagged != - UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); + (ug_info->vlanOperationTagged != UCC_GETH_VLAN_OPERATION_TAGGED_NOP) || + (ug_info->vlanOperationNonTagged != + UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); init_default_reg_vals(&uf_regs->upsmr, &ug_regs->maccfg1, &ug_regs->maccfg2); @@ -2987,11 +2987,11 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth->p_init_enet_param_shadow->rgftgfrxglobal |= ugeth->rx_glbl_pram_offset | ug_info->riscRx; if ((ug_info->largestexternallookupkeysize != - QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE) - && (ug_info->largestexternallookupkeysize != - QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES) - && (ug_info->largestexternallookupkeysize != - QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) { + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE) && + (ug_info->largestexternallookupkeysize != + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES) && + (ug_info->largestexternallookupkeysize != + QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Invalid largest External Lookup Key Size.", __func__); diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 1bef39a60a6..a516185cbc9 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -365,8 +365,8 @@ static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, padlen = ((skb->len + 4) % 512) ? 0 : 4; - if ((!skb_cloned(skb)) - && ((headroom + tailroom) >= (4 + padlen))) { + if ((!skb_cloned(skb)) && + ((headroom + tailroom) >= (4 + padlen))) { if ((headroom < 4) || (tailroom < padlen)) { skb->data = memmove(skb->head + 4, skb->data, skb->len); skb_set_tail_pointer(skb, skb->len); @@ -541,8 +541,8 @@ static void asix_set_multicast(struct net_device *net) if (net->flags & IFF_PROMISC) { rx_ctl |= AX_RX_CTL_PRO; - } else if (net->flags & IFF_ALLMULTI - || net->mc_count > AX_MAX_MCAST) { + } else if (net->flags & IFF_ALLMULTI || + net->mc_count > AX_MAX_MCAST) { rx_ctl |= AX_RX_CTL_AMALL; } else if (net->mc_count == 0) { /* just broadcast and directed */ @@ -753,8 +753,8 @@ static void ax88172_set_multicast(struct net_device *net) if (net->flags & IFF_PROMISC) { rx_ctl |= 0x01; - } else if (net->flags & IFF_ALLMULTI - || net->mc_count > AX_MAX_MCAST) { + } else if (net->flags & IFF_ALLMULTI || + net->mc_count > AX_MAX_MCAST) { rx_ctl |= 0x02; } else if (net->mc_count == 0) { /* just broadcast and directed */ diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 2bed6b087d1..22b87e64a81 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -436,8 +436,8 @@ static netdev_tx_t catc_start_xmit(struct sk_buff *skb, clear_bit(TX_RUNNING, &catc->flags); } - if ((catc->is_f5u011 && catc->tx_ptr) - || (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2)))) + if ((catc->is_f5u011 && catc->tx_ptr) || + (catc->tx_ptr >= ((TX_MAX_BURST - 1) * (PKT_SZ + 2)))) netif_stop_queue(netdev); spin_unlock_irqrestore(&catc->tx_lock, flags); diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c index 33d5c579c5a..6491c9c00c8 100644 --- a/drivers/net/usb/cdc-phonet.c +++ b/drivers/net/usb/cdc-phonet.c @@ -372,12 +372,12 @@ int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id) /* Data interface has one inactive and one active setting */ if (data_intf->num_altsetting != 2) return -EINVAL; - if (data_intf->altsetting[0].desc.bNumEndpoints == 0 - && data_intf->altsetting[1].desc.bNumEndpoints == 2) + if (data_intf->altsetting[0].desc.bNumEndpoints == 0 && + data_intf->altsetting[1].desc.bNumEndpoints == 2) data_desc = data_intf->altsetting + 1; else - if (data_intf->altsetting[0].desc.bNumEndpoints == 2 - && data_intf->altsetting[1].desc.bNumEndpoints == 0) + if (data_intf->altsetting[0].desc.bNumEndpoints == 2 && + data_intf->altsetting[1].desc.bNumEndpoints == 0) data_desc = data_intf->altsetting; else return -EINVAL; diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 23300656c26..c337ffc3304 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -121,8 +121,8 @@ static struct sk_buff *eem_tx_fixup(struct usbnet *dev, struct sk_buff *skb, int headroom = skb_headroom(skb); int tailroom = skb_tailroom(skb); - if ((tailroom >= ETH_FCS_LEN + padlen) - && (headroom >= EEM_HEAD)) + if ((tailroom >= ETH_FCS_LEN + padlen) && + (headroom >= EEM_HEAD)) goto done; if ((headroom + tailroom) diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 7ec24c9b253..21e183a83b9 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -37,23 +37,23 @@ static int is_rndis(struct usb_interface_descriptor *desc) { - return desc->bInterfaceClass == USB_CLASS_COMM - && desc->bInterfaceSubClass == 2 - && desc->bInterfaceProtocol == 0xff; + return (desc->bInterfaceClass == USB_CLASS_COMM && + desc->bInterfaceSubClass == 2 && + desc->bInterfaceProtocol == 0xff); } static int is_activesync(struct usb_interface_descriptor *desc) { - return desc->bInterfaceClass == USB_CLASS_MISC - && desc->bInterfaceSubClass == 1 - && desc->bInterfaceProtocol == 1; + return (desc->bInterfaceClass == USB_CLASS_MISC && + desc->bInterfaceSubClass == 1 && + desc->bInterfaceProtocol == 1); } static int is_wireless_rndis(struct usb_interface_descriptor *desc) { - return desc->bInterfaceClass == USB_CLASS_WIRELESS_CONTROLLER - && desc->bInterfaceSubClass == 1 - && desc->bInterfaceProtocol == 3; + return (desc->bInterfaceClass == USB_CLASS_WIRELESS_CONTROLLER && + desc->bInterfaceSubClass == 1 && + desc->bInterfaceProtocol == 3); } #else @@ -116,9 +116,9 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf) /* this assumes that if there's a non-RNDIS vendor variant * of cdc-acm, it'll fail RNDIS requests cleanly. */ - rndis = is_rndis(&intf->cur_altsetting->desc) - || is_activesync(&intf->cur_altsetting->desc) - || is_wireless_rndis(&intf->cur_altsetting->desc); + rndis = (is_rndis(&intf->cur_altsetting->desc) || + is_activesync(&intf->cur_altsetting->desc) || + is_wireless_rndis(&intf->cur_altsetting->desc)); memset(info, 0, sizeof *info); info->control = intf; @@ -279,10 +279,10 @@ next_desc: dev->status = &info->control->cur_altsetting->endpoint [0]; desc = &dev->status->desc; - if (!usb_endpoint_is_int_in(desc) - || (le16_to_cpu(desc->wMaxPacketSize) - < sizeof(struct usb_cdc_notification)) - || !desc->bInterval) { + if (!usb_endpoint_is_int_in(desc) || + (le16_to_cpu(desc->wMaxPacketSize) + < sizeof(struct usb_cdc_notification)) || + !desc->bInterval) { dev_dbg(&intf->dev, "bad notification endpoint\n"); dev->status = NULL; } @@ -411,6 +411,12 @@ static int cdc_bind(struct usbnet *dev, struct usb_interface *intf) return 0; } +static int cdc_manage_power(struct usbnet *dev, int on) +{ + dev->intf->needs_remote_wakeup = on; + return 0; +} + static const struct driver_info cdc_info = { .description = "CDC Ethernet Device", .flags = FLAG_ETHER | FLAG_LINK_INTR, @@ -418,6 +424,7 @@ static const struct driver_info cdc_info = { .bind = cdc_bind, .unbind = usbnet_cdc_unbind, .status = cdc_status, + .manage_power = cdc_manage_power, }; static const struct driver_info mbm_info = { @@ -618,6 +625,8 @@ static struct usb_driver cdc_driver = { .disconnect = usbnet_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .reset_resume = usbnet_resume, + .supports_autosuspend = 1, }; diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index fa4e58196c2..f78f0903b07 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -378,7 +378,7 @@ static void dbg_dump(int line_count, const char *func_name, unsigned char *buf, } #define DUMP(buf_, len_) \ - dbg_dump(__LINE__, __func__, buf_, len_) + dbg_dump(__LINE__, __func__, (unsigned char *)buf_, len_) #define DUMP1(buf_, len_) \ do { \ @@ -602,9 +602,9 @@ static struct hso_serial *get_serial_by_shared_int_and_type( port = hso_mux_to_port(mux); for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { - if (serial_table[i] - && (dev2ser(serial_table[i])->shared_int == shared_int) - && ((serial_table[i]->port_spec & HSO_PORT_MASK) == port)) { + if (serial_table[i] && + (dev2ser(serial_table[i])->shared_int == shared_int) && + ((serial_table[i]->port_spec & HSO_PORT_MASK) == port)) { return dev2ser(serial_table[i]); } } @@ -846,8 +846,8 @@ static void hso_net_tx_timeout(struct net_device *net) dev_warn(&net->dev, "Tx timed out.\n"); /* Tear the waiting frame off the list */ - if (odev->mux_bulk_tx_urb - && (odev->mux_bulk_tx_urb->status == -EINPROGRESS)) + if (odev->mux_bulk_tx_urb && + (odev->mux_bulk_tx_urb->status == -EINPROGRESS)) usb_unlink_urb(odev->mux_bulk_tx_urb); /* Update statistics */ @@ -1020,9 +1020,9 @@ static void read_bulk_callback(struct urb *urb) u32 rest; u8 crc_check[4] = { 0xDE, 0xAD, 0xBE, 0xEF }; rest = urb->actual_length % odev->in_endp->wMaxPacketSize; - if (((rest == 5) || (rest == 6)) - && !memcmp(((u8 *) urb->transfer_buffer) + - urb->actual_length - 4, crc_check, 4)) { + if (((rest == 5) || (rest == 6)) && + !memcmp(((u8 *) urb->transfer_buffer) + + urb->actual_length - 4, crc_check, 4)) { urb->actual_length -= 4; } } @@ -1226,9 +1226,9 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) rest = urb->actual_length % serial->in_endp->wMaxPacketSize; - if (((rest == 5) || (rest == 6)) - && !memcmp(((u8 *) urb->transfer_buffer) + - urb->actual_length - 4, crc_check, 4)) { + if (((rest == 5) || (rest == 6)) && + !memcmp(((u8 *) urb->transfer_buffer) + + urb->actual_length - 4, crc_check, 4)) { urb->actual_length -= 4; } } @@ -1363,7 +1363,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) /* reset the rts and dtr */ /* do the actual close */ serial->open_count--; - kref_put(&serial->parent->ref, hso_serial_ref_free); + if (serial->open_count <= 0) { serial->open_count = 0; spin_lock_irq(&serial->serial_lock); @@ -1383,6 +1383,8 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp) usb_autopm_put_interface(serial->parent->interface); mutex_unlock(&serial->parent->mutex); + + kref_put(&serial->parent->ref, hso_serial_ref_free); } /* close the requested serial port */ @@ -1527,7 +1529,7 @@ static void tiocmget_intr_callback(struct urb *urb) dev_warn(&usb->dev, "hso received invalid serial state notification\n"); DUMP(serial_state_notification, - sizeof(hso_serial_state_notifation)) + sizeof(struct hso_serial_state_notification)); } else { UART_state_bitmap = le16_to_cpu(serial_state_notification-> @@ -2980,8 +2982,8 @@ static int hso_probe(struct usb_interface *interface, case HSO_INTF_BULK: /* It's a regular bulk interface */ - if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) - && !disable_net) + if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) && + !disable_net) hso_dev = hso_create_net_device(interface, port_spec); else hso_dev = @@ -3144,8 +3146,8 @@ static void hso_free_interface(struct usb_interface *interface) int i; for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) { - if (serial_table[i] - && (serial_table[i]->interface == interface)) { + if (serial_table[i] && + (serial_table[i]->interface == interface)) { hso_dev = dev2ser(serial_table[i]); spin_lock_irq(&hso_dev->serial_lock); tty = tty_kref_get(hso_dev->tty); @@ -3161,8 +3163,8 @@ static void hso_free_interface(struct usb_interface *interface) } for (i = 0; i < HSO_MAX_NET_DEVICES; i++) { - if (network_table[i] - && (network_table[i]->interface == interface)) { + if (network_table[i] && + (network_table[i]->interface == interface)) { struct rfkill *rfk = dev2net(network_table[i])->rfkill; /* hso_stop_net_device doesn't stop the net queue since * traffic needs to start it again when suspended */ diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 10873d96b2d..87374317f48 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -391,8 +391,8 @@ static void mcs7830_set_multicast(struct net_device *net) if (net->flags & IFF_PROMISC) { data->config |= HIF_REG_CONFIG_PROMISCIOUS; - } else if (net->flags & IFF_ALLMULTI - || net->mc_count > MCS7830_MAX_MCAST) { + } else if (net->flags & IFF_ALLMULTI || + net->mc_count > MCS7830_MAX_MCAST) { data->config |= HIF_REG_CONFIG_ALLMULTICAST; } else if (net->mc_count == 0) { /* just broadcast and directed */ diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index f56dec6119c..490fa8f5542 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -114,8 +114,8 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen) */ /* Issue the request; xid is unique, don't bother byteswapping it */ - if (likely(buf->msg_type != RNDIS_MSG_HALT - && buf->msg_type != RNDIS_MSG_RESET)) { + if (likely(buf->msg_type != RNDIS_MSG_HALT && + buf->msg_type != RNDIS_MSG_RESET)) { xid = dev->xid++; if (!xid) xid = dev->xid++; @@ -493,9 +493,9 @@ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) data_len = le32_to_cpu(hdr->data_len); /* don't choke if we see oob, per-packet data, etc */ - if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET - || skb->len < msg_len - || (data_offset + data_len + 8) > msg_len)) { + if (unlikely(hdr->msg_type != RNDIS_MSG_PACKET || + skb->len < msg_len || + (data_offset + data_len + 8) > msg_len)) { dev->net->stats.rx_frame_errors++; devdbg(dev, "bad rndis message %d/%d/%d/%d, len %d", le32_to_cpu(hdr->msg_type), diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 04f3f289e87..035fab04c0a 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -140,8 +140,8 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) if (!alt || !in || !out) return -EINVAL; - if (alt->desc.bAlternateSetting != 0 - || !(dev->driver_info->flags & FLAG_NO_SETINT)) { + if (alt->desc.bAlternateSetting != 0 || + !(dev->driver_info->flags & FLAG_NO_SETINT)) { tmp = usb_set_interface (dev->udev, alt->desc.bInterfaceNumber, alt->desc.bAlternateSetting); if (tmp < 0) @@ -351,9 +351,10 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) spin_lock_irqsave (&dev->rxq.lock, lockflags); - if (netif_running (dev->net) - && netif_device_present (dev->net) - && !test_bit (EVENT_RX_HALT, &dev->flags)) { + if (netif_running (dev->net) && + netif_device_present (dev->net) && + !test_bit (EVENT_RX_HALT, &dev->flags) && + !test_bit (EVENT_DEV_ASLEEP, &dev->flags)) { switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) { case -EPIPE: usbnet_defer_kevent (dev, EVENT_RX_HALT); @@ -391,8 +392,8 @@ static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags) static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) { - if (dev->driver_info->rx_fixup - && !dev->driver_info->rx_fixup (dev, skb)) + if (dev->driver_info->rx_fixup && + !dev->driver_info->rx_fixup (dev, skb)) goto error; // else network stack removes extra byte if we forced a short packet @@ -484,8 +485,8 @@ block: defer_bh(dev, skb, &dev->rxq); if (urb) { - if (netif_running (dev->net) - && !test_bit (EVENT_RX_HALT, &dev->flags)) { + if (netif_running (dev->net) && + !test_bit (EVENT_RX_HALT, &dev->flags)) { rx_submit (dev, urb, GFP_ATOMIC); return; } @@ -611,15 +612,39 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); /*-------------------------------------------------------------------------*/ // precondition: never called in_interrupt +static void usbnet_terminate_urbs(struct usbnet *dev) +{ + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup); + DECLARE_WAITQUEUE(wait, current); + int temp; + + /* ensure there are no more active urbs */ + add_wait_queue(&unlink_wakeup, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + dev->wait = &unlink_wakeup; + temp = unlink_urbs(dev, &dev->txq) + + unlink_urbs(dev, &dev->rxq); + + /* maybe wait for deletions to finish. */ + while (!skb_queue_empty(&dev->rxq) + && !skb_queue_empty(&dev->txq) + && !skb_queue_empty(&dev->done)) { + schedule_timeout(UNLINK_TIMEOUT_MS); + set_current_state(TASK_UNINTERRUPTIBLE); + if (netif_msg_ifdown(dev)) + devdbg(dev, "waited for %d urb completions", + temp); + } + set_current_state(TASK_RUNNING); + dev->wait = NULL; + remove_wait_queue(&unlink_wakeup, &wait); +} int usbnet_stop (struct net_device *net) { struct usbnet *dev = netdev_priv(net); struct driver_info *info = dev->driver_info; - int temp; int retval; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); - DECLARE_WAITQUEUE (wait, current); netif_stop_queue (net); @@ -641,25 +666,8 @@ int usbnet_stop (struct net_device *net) info->description); } - if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { - /* ensure there are no more active urbs */ - add_wait_queue(&unlink_wakeup, &wait); - dev->wait = &unlink_wakeup; - temp = unlink_urbs(dev, &dev->txq) + - unlink_urbs(dev, &dev->rxq); - - /* maybe wait for deletions to finish. */ - while (!skb_queue_empty(&dev->rxq) - && !skb_queue_empty(&dev->txq) - && !skb_queue_empty(&dev->done)) { - msleep(UNLINK_TIMEOUT_MS); - if (netif_msg_ifdown(dev)) - devdbg(dev, "waited for %d urb completions", - temp); - } - dev->wait = NULL; - remove_wait_queue(&unlink_wakeup, &wait); - } + if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) + usbnet_terminate_urbs(dev); usb_kill_urb(dev->interrupt); @@ -672,7 +680,10 @@ int usbnet_stop (struct net_device *net) dev->flags = 0; del_timer_sync (&dev->delay); tasklet_kill (&dev->bh); - usb_autopm_put_interface(dev->intf); + if (info->manage_power) + info->manage_power(dev, 0); + else + usb_autopm_put_interface(dev->intf); return 0; } @@ -753,6 +764,12 @@ int usbnet_open (struct net_device *net) // delay posting reads until we're fully open tasklet_schedule (&dev->bh); + if (info->manage_power) { + retval = info->manage_power(dev, 1); + if (retval < 0) + goto done; + usb_autopm_put_interface(dev->intf); + } return retval; done: usb_autopm_put_interface(dev->intf); @@ -881,11 +898,16 @@ kevent (struct work_struct *work) /* usb_clear_halt() needs a thread context */ if (test_bit (EVENT_TX_HALT, &dev->flags)) { unlink_urbs (dev, &dev->txq); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto fail_pipe; status = usb_clear_halt (dev->udev, dev->out); - if (status < 0 - && status != -EPIPE - && status != -ESHUTDOWN) { + usb_autopm_put_interface(dev->intf); + if (status < 0 && + status != -EPIPE && + status != -ESHUTDOWN) { if (netif_msg_tx_err (dev)) +fail_pipe: deverr (dev, "can't clear tx halt, status %d", status); } else { @@ -896,11 +918,16 @@ kevent (struct work_struct *work) } if (test_bit (EVENT_RX_HALT, &dev->flags)) { unlink_urbs (dev, &dev->rxq); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto fail_halt; status = usb_clear_halt (dev->udev, dev->in); - if (status < 0 - && status != -EPIPE - && status != -ESHUTDOWN) { + usb_autopm_put_interface(dev->intf); + if (status < 0 && + status != -EPIPE && + status != -ESHUTDOWN) { if (netif_msg_rx_err (dev)) +fail_halt: deverr (dev, "can't clear rx halt, status %d", status); } else { @@ -919,7 +946,12 @@ kevent (struct work_struct *work) clear_bit (EVENT_RX_MEMORY, &dev->flags); if (urb != NULL) { clear_bit (EVENT_RX_MEMORY, &dev->flags); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto fail_lowmem; rx_submit (dev, urb, GFP_KERNEL); + usb_autopm_put_interface(dev->intf); +fail_lowmem: tasklet_schedule (&dev->bh); } } @@ -929,11 +961,18 @@ kevent (struct work_struct *work) int retval = 0; clear_bit (EVENT_LINK_RESET, &dev->flags); + status = usb_autopm_get_interface(dev->intf); + if (status < 0) + goto skip_reset; if(info->link_reset && (retval = info->link_reset(dev)) < 0) { + usb_autopm_put_interface(dev->intf); +skip_reset: devinfo(dev, "link reset failed (%d) usbnet usb-%s-%s, %s", retval, dev->udev->bus->bus_name, dev->udev->devpath, info->description); + } else { + usb_autopm_put_interface(dev->intf); } } @@ -971,6 +1010,7 @@ static void tx_complete (struct urb *urb) case -EPROTO: case -ETIME: case -EILSEQ: + usb_mark_last_busy(dev->udev); if (!timer_pending (&dev->delay)) { mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES); @@ -987,6 +1027,7 @@ static void tx_complete (struct urb *urb) } } + usb_autopm_put_interface_async(dev->intf); urb->dev = NULL; entry->state = tx_done; defer_bh(dev, skb, &dev->txq); @@ -1057,14 +1098,34 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, } } - spin_lock_irqsave (&dev->txq.lock, flags); + spin_lock_irqsave(&dev->txq.lock, flags); + retval = usb_autopm_get_interface_async(dev->intf); + if (retval < 0) { + spin_unlock_irqrestore(&dev->txq.lock, flags); + goto drop; + } + +#ifdef CONFIG_PM + /* if this triggers the device is still a sleep */ + if (test_bit(EVENT_DEV_ASLEEP, &dev->flags)) { + /* transmission will be done in resume */ + usb_anchor_urb(urb, &dev->deferred); + /* no use to process more packets */ + netif_stop_queue(net); + spin_unlock_irqrestore(&dev->txq.lock, flags); + devdbg(dev, "Delaying transmission for resumption"); + goto deferred; + } +#endif switch ((retval = usb_submit_urb (urb, GFP_ATOMIC))) { case -EPIPE: netif_stop_queue (net); usbnet_defer_kevent (dev, EVENT_TX_HALT); + usb_autopm_put_interface_async(dev->intf); break; default: + usb_autopm_put_interface_async(dev->intf); if (netif_msg_tx_err (dev)) devdbg (dev, "tx: submit urb err %d", retval); break; @@ -1088,6 +1149,9 @@ drop: devdbg (dev, "> tx, len %d, type 0x%x", length, skb->protocol); } +#ifdef CONFIG_PM +deferred: +#endif return NETDEV_TX_OK; } EXPORT_SYMBOL_GPL(usbnet_start_xmit); @@ -1126,10 +1190,10 @@ static void usbnet_bh (unsigned long param) } // or are we maybe short a few urbs? - } else if (netif_running (dev->net) - && netif_device_present (dev->net) - && !timer_pending (&dev->delay) - && !test_bit (EVENT_RX_HALT, &dev->flags)) { + } else if (netif_running (dev->net) && + netif_device_present (dev->net) && + !timer_pending (&dev->delay) && + !test_bit (EVENT_RX_HALT, &dev->flags)) { int temp = dev->rxq.qlen; int qlen = RX_QLEN (dev); @@ -1263,6 +1327,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) dev->bh.func = usbnet_bh; dev->bh.data = (unsigned long) dev; INIT_WORK (&dev->kevent, kevent); + init_usb_anchor(&dev->deferred); dev->delay.function = usbnet_bh; dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); @@ -1297,8 +1362,8 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) // heuristic: "usb%d" for links we know are two-host, // else "eth%d" when there's reasonable doubt. userspace // can rename the link if it knows better. - if ((dev->driver_info->flags & FLAG_ETHER) != 0 - && (net->dev_addr [0] & 0x02) == 0) + if ((dev->driver_info->flags & FLAG_ETHER) != 0 && + (net->dev_addr [0] & 0x02) == 0) strcpy (net->name, "eth%d"); /* WLAN devices should always be named "wlan%d" */ if ((dev->driver_info->flags & FLAG_WLAN) != 0) @@ -1382,13 +1447,23 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) struct usbnet *dev = usb_get_intfdata(intf); if (!dev->suspend_count++) { + spin_lock_irq(&dev->txq.lock); + /* don't autosuspend while transmitting */ + if (dev->txq.qlen && (message.event & PM_EVENT_AUTO)) { + spin_unlock_irq(&dev->txq.lock); + return -EBUSY; + } else { + set_bit(EVENT_DEV_ASLEEP, &dev->flags); + spin_unlock_irq(&dev->txq.lock); + } /* * accelerate emptying of the rx and queues, to avoid * having everything error out. */ netif_device_detach (dev->net); - (void) unlink_urbs (dev, &dev->rxq); - (void) unlink_urbs (dev, &dev->txq); + usbnet_terminate_urbs(dev); + usb_kill_urb(dev->interrupt); + /* * reattach so runtime management can use and * wake the device @@ -1402,10 +1477,34 @@ EXPORT_SYMBOL_GPL(usbnet_suspend); int usbnet_resume (struct usb_interface *intf) { struct usbnet *dev = usb_get_intfdata(intf); + struct sk_buff *skb; + struct urb *res; + int retval; + + if (!--dev->suspend_count) { + spin_lock_irq(&dev->txq.lock); + while ((res = usb_get_from_anchor(&dev->deferred))) { + + printk(KERN_INFO"%s has delayed data\n", __func__); + skb = (struct sk_buff *)res->context; + retval = usb_submit_urb(res, GFP_ATOMIC); + if (retval < 0) { + dev_kfree_skb_any(skb); + usb_free_urb(res); + usb_autopm_put_interface_async(dev->intf); + } else { + dev->net->trans_start = jiffies; + __skb_queue_tail(&dev->txq, skb); + } + } - if (!--dev->suspend_count) + smp_mb(); + clear_bit(EVENT_DEV_ASLEEP, &dev->flags); + spin_unlock_irq(&dev->txq.lock); + if (!(dev->txq.qlen >= TX_QLEN(dev))) + netif_start_queue(dev->net); tasklet_schedule (&dev->bh); - + } return 0; } EXPORT_SYMBOL_GPL(usbnet_resume); diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index 04882c8f9bf..3eb0b167b5b 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -174,8 +174,8 @@ static int blan_mdlm_bind(struct usbnet *dev, struct usb_interface *intf) goto bad_desc; } /* expect bcdVersion 1.0, ignore */ - if (memcmp(&desc->bGUID, blan_guid, 16) - && memcmp(&desc->bGUID, safe_guid, 16) ) { + if (memcmp(&desc->bGUID, blan_guid, 16) && + memcmp(&desc->bGUID, safe_guid, 16)) { /* hey, this one might _really_ be MDLM! */ dev_dbg(&intf->dev, "MDLM guid\n"); goto bad_desc; diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2d657f2314c..63099c58a6d 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -155,8 +155,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) struct veth_net_stats *stats, *rcv_stats; int length, cpu; - skb_orphan(skb); - priv = netdev_priv(dev); rcv = priv->peer; rcv_priv = netdev_priv(rcv); @@ -168,20 +166,12 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) if (!(rcv->flags & IFF_UP)) goto tx_drop; - if (skb->len > (rcv->mtu + MTU_PAD)) - goto rx_drop; - - skb->tstamp.tv64 = 0; - skb->pkt_type = PACKET_HOST; - skb->protocol = eth_type_trans(skb, rcv); if (dev->features & NETIF_F_NO_CSUM) skb->ip_summed = rcv_priv->ip_summed; - skb->mark = 0; - secpath_reset(skb); - nf_reset(skb); - - length = skb->len; + length = skb->len + ETH_HLEN; + if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS) + goto rx_drop; stats->tx_bytes += length; stats->tx_packets++; @@ -189,7 +179,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) rcv_stats->rx_bytes += length; rcv_stats->rx_packets++; - netif_rx(skb); return NETDEV_TX_OK; tx_drop: @@ -210,32 +199,29 @@ rx_drop: static struct net_device_stats *veth_get_stats(struct net_device *dev) { struct veth_priv *priv; - struct net_device_stats *dev_stats; int cpu; - struct veth_net_stats *stats; + struct veth_net_stats *stats, total = {0}; priv = netdev_priv(dev); - dev_stats = &dev->stats; - dev_stats->rx_packets = 0; - dev_stats->tx_packets = 0; - dev_stats->rx_bytes = 0; - dev_stats->tx_bytes = 0; - dev_stats->tx_dropped = 0; - dev_stats->rx_dropped = 0; - - for_each_online_cpu(cpu) { + for_each_possible_cpu(cpu) { stats = per_cpu_ptr(priv->stats, cpu); - dev_stats->rx_packets += stats->rx_packets; - dev_stats->tx_packets += stats->tx_packets; - dev_stats->rx_bytes += stats->rx_bytes; - dev_stats->tx_bytes += stats->tx_bytes; - dev_stats->tx_dropped += stats->tx_dropped; - dev_stats->rx_dropped += stats->rx_dropped; + total.rx_packets += stats->rx_packets; + total.tx_packets += stats->tx_packets; + total.rx_bytes += stats->rx_bytes; + total.tx_bytes += stats->tx_bytes; + total.tx_dropped += stats->tx_dropped; + total.rx_dropped += stats->rx_dropped; } - - return dev_stats; + dev->stats.rx_packets = total.rx_packets; + dev->stats.tx_packets = total.tx_packets; + dev->stats.rx_bytes = total.rx_bytes; + dev->stats.tx_bytes = total.tx_bytes; + dev->stats.tx_dropped = total.tx_dropped; + dev->stats.rx_dropped = total.rx_dropped; + + return &dev->stats; } static int veth_open(struct net_device *dev) diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index ec94ddf01f5..593e01f64e9 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -42,9 +42,9 @@ static int max_interrupt_work = 20; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ -#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(CONFIG_SPARC) || defined(__ia64__) \ - || defined(__sh__) || defined(__mips__) +#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) || \ + defined(CONFIG_SPARC) || defined(__ia64__) || \ + defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else static int rx_copybreak; @@ -1683,8 +1683,8 @@ static void rhine_set_rx_mode(struct net_device *dev) rx_mode = 0x1C; iowrite32(0xffffffff, ioaddr + MulticastFilter0); iowrite32(0xffffffff, ioaddr + MulticastFilter1); - } else if ((dev->mc_count > multicast_filter_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { /* Too many to match, or accept all multicasts. */ iowrite32(0xffffffff, ioaddr + MulticastFilter0); iowrite32(0xffffffff, ioaddr + MulticastFilter1); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 1e6b395c555..4ceb441f268 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -9,7 +9,6 @@ * * TODO * rx_copybreak/alignment - * Scatter gather * More testing * * The changes are (c) Copyright 2004, Red Hat Inc. <alan@lxorguk.ukuu.org.uk> @@ -275,7 +274,7 @@ VELOCITY_PARAM(rx_thresh, "Receive fifo threshold"); #define DMA_LENGTH_MIN 0 #define DMA_LENGTH_MAX 7 -#define DMA_LENGTH_DEF 0 +#define DMA_LENGTH_DEF 6 /* DMA_length[] is used for controlling the DMA length 0: 8 DWORDs @@ -298,14 +297,6 @@ VELOCITY_PARAM(DMA_length, "DMA length"); */ VELOCITY_PARAM(IP_byte_align, "Enable IP header dword aligned"); -#define TX_CSUM_DEF 1 -/* txcsum_offload[] is used for setting the checksum offload ability of NIC. - (We only support RX checksum offload now) - 0: disable csum_offload[checksum offload - 1: enable checksum offload. (Default) -*/ -VELOCITY_PARAM(txcsum_offload, "Enable transmit packet checksum offload"); - #define FLOW_CNTL_DEF 1 #define FLOW_CNTL_MIN 1 #define FLOW_CNTL_MAX 5 @@ -354,12 +345,6 @@ VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame"); */ VELOCITY_PARAM(wol_opts, "Wake On Lan options"); -#define INT_WORKS_DEF 20 -#define INT_WORKS_MIN 10 -#define INT_WORKS_MAX 64 - -VELOCITY_PARAM(int_works, "Number of packets per interrupt services"); - static int rx_copybreak = 200; module_param(rx_copybreak, int, 0644); MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); @@ -497,13 +482,11 @@ static void __devinit velocity_get_options(struct velocity_opt *opts, int index, velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname); velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname); - velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname); velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname); velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname); velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname); velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname); velocity_set_int_opt((int *) &opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname); - velocity_set_int_opt((int *) &opts->int_works, int_works[index], INT_WORKS_MIN, INT_WORKS_MAX, INT_WORKS_DEF, "Interrupt service works", devname); opts->numrx = (opts->numrx & ~3); } @@ -912,8 +895,8 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status) /* Check if new status is consisent with current status - if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) - || (mii_status==curr_status)) { + if (((mii_status & curr_status) & VELOCITY_AUTONEG_ENABLE) || + (mii_status==curr_status)) { vptr->mii_status=mii_check_media_mode(vptr->mac_regs); vptr->mii_status=check_connection_type(vptr->mac_regs); VELOCITY_PRT(MSG_LEVEL_INFO, "Velocity link no change\n"); @@ -1149,8 +1132,8 @@ static void velocity_set_multi(struct net_device *dev) writel(0xffffffff, ®s->MARCAM[0]); writel(0xffffffff, ®s->MARCAM[4]); rx_mode = (RCR_AM | RCR_AB | RCR_PROM); - } else if ((dev->mc_count > vptr->multicast_limit) - || (dev->flags & IFF_ALLMULTI)) { + } else if ((dev->mc_count > vptr->multicast_limit) || + (dev->flags & IFF_ALLMULTI)) { writel(0xffffffff, ®s->MARCAM[0]); writel(0xffffffff, ®s->MARCAM[4]); rx_mode = (RCR_AM | RCR_AB); @@ -1246,6 +1229,66 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status) } } +/** + * setup_queue_timers - Setup interrupt timers + * + * Setup interrupt frequency during suppression (timeout if the frame + * count isn't filled). + */ +static void setup_queue_timers(struct velocity_info *vptr) +{ + /* Only for newer revisions */ + if (vptr->rev_id >= REV_ID_VT3216_A0) { + u8 txqueue_timer = 0; + u8 rxqueue_timer = 0; + + if (vptr->mii_status & (VELOCITY_SPEED_1000 | + VELOCITY_SPEED_100)) { + txqueue_timer = vptr->options.txqueue_timer; + rxqueue_timer = vptr->options.rxqueue_timer; + } + + writeb(txqueue_timer, &vptr->mac_regs->TQETMR); + writeb(rxqueue_timer, &vptr->mac_regs->RQETMR); + } +} +/** + * setup_adaptive_interrupts - Setup interrupt suppression + * + * @vptr velocity adapter + * + * The velocity is able to suppress interrupt during high interrupt load. + * This function turns on that feature. + */ +static void setup_adaptive_interrupts(struct velocity_info *vptr) +{ + struct mac_regs __iomem *regs = vptr->mac_regs; + u16 tx_intsup = vptr->options.tx_intsup; + u16 rx_intsup = vptr->options.rx_intsup; + + /* Setup default interrupt mask (will be changed below) */ + vptr->int_mask = INT_MASK_DEF; + + /* Set Tx Interrupt Suppression Threshold */ + writeb(CAMCR_PS0, ®s->CAMCR); + if (tx_intsup != 0) { + vptr->int_mask &= ~(ISR_PTXI | ISR_PTX0I | ISR_PTX1I | + ISR_PTX2I | ISR_PTX3I); + writew(tx_intsup, ®s->ISRCTL); + } else + writew(ISRCTL_TSUPDIS, ®s->ISRCTL); + + /* Set Rx Interrupt Suppression Threshold */ + writeb(CAMCR_PS1, ®s->CAMCR); + if (rx_intsup != 0) { + vptr->int_mask &= ~ISR_PRXI; + writew(rx_intsup, ®s->ISRCTL); + } else + writew(ISRCTL_RSUPDIS, ®s->ISRCTL); + + /* Select page to interrupt hold timer */ + writeb(0, ®s->CAMCR); +} /** * velocity_init_registers - initialise MAC registers @@ -1332,7 +1375,7 @@ static void velocity_init_registers(struct velocity_info *vptr, */ enable_mii_autopoll(regs); - vptr->int_mask = INT_MASK_DEF; + setup_adaptive_interrupts(vptr); writel(vptr->rx.pool_dma, ®s->RDBaseLo); writew(vptr->options.numrx - 1, ®s->RDCSize); @@ -1470,7 +1513,8 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx) * Do the gymnastics to get the buffer head for data at * 64byte alignment. */ - skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63); + skb_reserve(rd_info->skb, + 64 - ((unsigned long) rd_info->skb->data & 63)); rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx.buf_sz, PCI_DMA_FROMDEVICE); @@ -1589,12 +1633,10 @@ out: */ static int velocity_init_td_ring(struct velocity_info *vptr) { - dma_addr_t curr; int j; /* Init the TD ring entries */ for (j = 0; j < vptr->tx.numq; j++) { - curr = vptr->tx.pool_dma[j]; vptr->tx.infos[j] = kcalloc(vptr->options.numtx, sizeof(struct velocity_td_info), @@ -1660,21 +1702,27 @@ err_free_dma_rings_0: * Release an transmit buffer. If the buffer was preallocated then * recycle it, if not then unmap the buffer. */ -static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo) +static void velocity_free_tx_buf(struct velocity_info *vptr, + struct velocity_td_info *tdinfo, struct tx_desc *td) { struct sk_buff *skb = tdinfo->skb; - int i; - int pktlen; /* * Don't unmap the pre-allocated tx_bufs */ if (tdinfo->skb_dma) { + int i; - pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); for (i = 0; i < tdinfo->nskb_dma; i++) { - pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE); - tdinfo->skb_dma[i] = 0; + size_t pktlen = max_t(size_t, skb->len, ETH_ZLEN); + + /* For scatter-gather */ + if (skb_shinfo(skb)->nr_frags > 0) + pktlen = max_t(size_t, pktlen, + td->td_buf[i].size & ~TD_QUEUE); + + pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], + le16_to_cpu(pktlen), PCI_DMA_TODEVICE); } } dev_kfree_skb_irq(skb); @@ -1788,6 +1836,8 @@ static void velocity_error(struct velocity_info *vptr, int status) BYTE_REG_BITS_OFF(TESTCFG_HBDIS, ®s->TESTCFG); else BYTE_REG_BITS_ON(TESTCFG_HBDIS, ®s->TESTCFG); + + setup_queue_timers(vptr); } /* * Get link status from PHYSR0 @@ -1874,7 +1924,7 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status) stats->tx_packets++; stats->tx_bytes += tdinfo->skb->len; } - velocity_free_tx_buf(vptr, tdinfo); + velocity_free_tx_buf(vptr, tdinfo, td); vptr->tx.used[qnum]--; } vptr->tx.tail[qnum] = idx; @@ -1886,8 +1936,8 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status) * Look to see if we should kick the transmit network * layer for more work. */ - if (netif_queue_stopped(vptr->dev) && (full == 0) - && (!(vptr->mii_status & VELOCITY_LINK_FAIL))) { + if (netif_queue_stopped(vptr->dev) && (full == 0) && + (!(vptr->mii_status & VELOCITY_LINK_FAIL))) { netif_wake_queue(vptr->dev); } return works; @@ -2046,13 +2096,14 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) * any received packets from the receive queue. Hand the ring * slots back to the adapter for reuse. */ -static int velocity_rx_srv(struct velocity_info *vptr, int status) +static int velocity_rx_srv(struct velocity_info *vptr, int status, + int budget_left) { struct net_device_stats *stats = &vptr->dev->stats; int rd_curr = vptr->rx.curr; int works = 0; - do { + while (works < budget_left) { struct rx_desc *rd = vptr->rx.ring + rd_curr; if (!vptr->rx.info[rd_curr].skb) @@ -2083,7 +2134,8 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status) rd_curr++; if (rd_curr >= vptr->options.numrx) rd_curr = 0; - } while (++works <= 15); + works++; + } vptr->rx.curr = rd_curr; @@ -2094,6 +2146,40 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status) return works; } +static int velocity_poll(struct napi_struct *napi, int budget) +{ + struct velocity_info *vptr = container_of(napi, + struct velocity_info, napi); + unsigned int rx_done; + u32 isr_status; + + spin_lock(&vptr->lock); + isr_status = mac_read_isr(vptr->mac_regs); + + /* Ack the interrupt */ + mac_write_isr(vptr->mac_regs, isr_status); + if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI))) + velocity_error(vptr, isr_status); + + /* + * Do rx and tx twice for performance (taken from the VIA + * out-of-tree driver). + */ + rx_done = velocity_rx_srv(vptr, isr_status, budget / 2); + velocity_tx_srv(vptr, isr_status); + rx_done += velocity_rx_srv(vptr, isr_status, budget - rx_done); + velocity_tx_srv(vptr, isr_status); + + spin_unlock(&vptr->lock); + + /* If budget not fully consumed, exit the polling mode */ + if (rx_done < budget) { + napi_complete(napi); + mac_enable_int(vptr->mac_regs); + } + + return rx_done; +} /** * velocity_intr - interrupt callback @@ -2110,8 +2196,6 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance) struct net_device *dev = dev_instance; struct velocity_info *vptr = netdev_priv(dev); u32 isr_status; - int max_count = 0; - spin_lock(&vptr->lock); isr_status = mac_read_isr(vptr->mac_regs); @@ -2122,32 +2206,13 @@ static irqreturn_t velocity_intr(int irq, void *dev_instance) return IRQ_NONE; } - mac_disable_int(vptr->mac_regs); - - /* - * Keep processing the ISR until we have completed - * processing and the isr_status becomes zero - */ - - while (isr_status != 0) { - mac_write_isr(vptr->mac_regs, isr_status); - if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI))) - velocity_error(vptr, isr_status); - if (isr_status & (ISR_PRXI | ISR_PPRXI)) - max_count += velocity_rx_srv(vptr, isr_status); - if (isr_status & (ISR_PTXI | ISR_PPTXI)) - max_count += velocity_tx_srv(vptr, isr_status); - isr_status = mac_read_isr(vptr->mac_regs); - if (max_count > vptr->options.int_works) { - printk(KERN_WARNING "%s: excessive work at interrupt.\n", - dev->name); - max_count = 0; - } + if (likely(napi_schedule_prep(&vptr->napi))) { + mac_disable_int(vptr->mac_regs); + __napi_schedule(&vptr->napi); } spin_unlock(&vptr->lock); - mac_enable_int(vptr->mac_regs); - return IRQ_HANDLED; + return IRQ_HANDLED; } /** @@ -2187,6 +2252,7 @@ static int velocity_open(struct net_device *dev) mac_enable_int(vptr->mac_regs); netif_start_queue(dev); + napi_enable(&vptr->napi); vptr->flags |= VELOCITY_FLAGS_OPENED; out: return ret; @@ -2422,6 +2488,7 @@ static int velocity_close(struct net_device *dev) { struct velocity_info *vptr = netdev_priv(dev); + napi_disable(&vptr->napi); netif_stop_queue(dev); velocity_shutdown(vptr); @@ -2456,14 +2523,22 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, struct velocity_td_info *tdinfo; unsigned long flags; int pktlen; - __le16 len; - int index; + int index, prev; + int i = 0; if (skb_padto(skb, ETH_ZLEN)) goto out; - pktlen = max_t(unsigned int, skb->len, ETH_ZLEN); - len = cpu_to_le16(pktlen); + /* The hardware can handle at most 7 memory segments, so merge + * the skb if there are more */ + if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) { + kfree_skb(skb); + return NETDEV_TX_OK; + } + + pktlen = skb_shinfo(skb)->nr_frags == 0 ? + max_t(unsigned int, skb->len, ETH_ZLEN) : + skb_headlen(skb); spin_lock_irqsave(&vptr->lock, flags); @@ -2480,11 +2555,24 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, */ tdinfo->skb = skb; tdinfo->skb_dma[0] = pci_map_single(vptr->pdev, skb->data, pktlen, PCI_DMA_TODEVICE); - td_ptr->tdesc0.len = len; + td_ptr->tdesc0.len = cpu_to_le16(pktlen); td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]); td_ptr->td_buf[0].pa_high = 0; - td_ptr->td_buf[0].size = len; - tdinfo->nskb_dma = 1; + td_ptr->td_buf[0].size = cpu_to_le16(pktlen); + + /* Handle fragments */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + tdinfo->skb_dma[i + 1] = pci_map_page(vptr->pdev, frag->page, + frag->page_offset, frag->size, + PCI_DMA_TODEVICE); + + td_ptr->td_buf[i + 1].pa_low = cpu_to_le32(tdinfo->skb_dma[i + 1]); + td_ptr->td_buf[i + 1].pa_high = 0; + td_ptr->td_buf[i + 1].size = cpu_to_le16(frag->size); + } + tdinfo->nskb_dma = i + 1; td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16; @@ -2496,8 +2584,8 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, /* * Handle hardware checksum */ - if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM) - && (skb->ip_summed == CHECKSUM_PARTIAL)) { + if ((dev->features & NETIF_F_IP_CSUM) && + (skb->ip_summed == CHECKSUM_PARTIAL)) { const struct iphdr *ip = ip_hdr(skb); if (ip->protocol == IPPROTO_TCP) td_ptr->tdesc1.TCR |= TCR0_TCPCK; @@ -2505,23 +2593,21 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb, td_ptr->tdesc1.TCR |= (TCR0_UDPCK); td_ptr->tdesc1.TCR |= TCR0_IPCK; } - { - int prev = index - 1; + prev = index - 1; + if (prev < 0) + prev = vptr->options.numtx - 1; + td_ptr->tdesc0.len |= OWNED_BY_NIC; + vptr->tx.used[qnum]++; + vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx; - if (prev < 0) - prev = vptr->options.numtx - 1; - td_ptr->tdesc0.len |= OWNED_BY_NIC; - vptr->tx.used[qnum]++; - vptr->tx.curr[qnum] = (index + 1) % vptr->options.numtx; + if (AVAIL_TD(vptr, qnum) < 1) + netif_stop_queue(dev); - if (AVAIL_TD(vptr, qnum) < 1) - netif_stop_queue(dev); + td_ptr = &(vptr->tx.rings[qnum][prev]); + td_ptr->td_buf[0].size |= TD_QUEUE; + mac_tx_queue_wake(vptr->mac_regs, qnum); - td_ptr = &(vptr->tx.rings[qnum][prev]); - td_ptr->td_buf[0].size |= TD_QUEUE; - mac_tx_queue_wake(vptr->mac_regs, qnum); - } dev->trans_start = jiffies; spin_unlock_irqrestore(&vptr->lock, flags); out: @@ -2740,12 +2826,10 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi dev->irq = pdev->irq; dev->netdev_ops = &velocity_netdev_ops; dev->ethtool_ops = &velocity_ethtool_ops; + netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT); dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | - NETIF_F_HW_VLAN_RX; - - if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) - dev->features |= NETIF_F_IP_CSUM; + NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM; ret = register_netdev(dev); if (ret < 0) @@ -3198,15 +3282,114 @@ static void velocity_set_msglevel(struct net_device *dev, u32 value) msglevel = value; } +static int get_pending_timer_val(int val) +{ + int mult_bits = val >> 6; + int mult = 1; + + switch (mult_bits) + { + case 1: + mult = 4; break; + case 2: + mult = 16; break; + case 3: + mult = 64; break; + case 0: + default: + break; + } + + return (val & 0x3f) * mult; +} + +static void set_pending_timer_val(int *val, u32 us) +{ + u8 mult = 0; + u8 shift = 0; + + if (us >= 0x3f) { + mult = 1; /* mult with 4 */ + shift = 2; + } + if (us >= 0x3f * 4) { + mult = 2; /* mult with 16 */ + shift = 4; + } + if (us >= 0x3f * 16) { + mult = 3; /* mult with 64 */ + shift = 6; + } + + *val = (mult << 6) | ((us >> shift) & 0x3f); +} + + +static int velocity_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *ecmd) +{ + struct velocity_info *vptr = netdev_priv(dev); + + ecmd->tx_max_coalesced_frames = vptr->options.tx_intsup; + ecmd->rx_max_coalesced_frames = vptr->options.rx_intsup; + + ecmd->rx_coalesce_usecs = get_pending_timer_val(vptr->options.rxqueue_timer); + ecmd->tx_coalesce_usecs = get_pending_timer_val(vptr->options.txqueue_timer); + + return 0; +} + +static int velocity_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *ecmd) +{ + struct velocity_info *vptr = netdev_priv(dev); + int max_us = 0x3f * 64; + + /* 6 bits of */ + if (ecmd->tx_coalesce_usecs > max_us) + return -EINVAL; + if (ecmd->rx_coalesce_usecs > max_us) + return -EINVAL; + + if (ecmd->tx_max_coalesced_frames > 0xff) + return -EINVAL; + if (ecmd->rx_max_coalesced_frames > 0xff) + return -EINVAL; + + vptr->options.rx_intsup = ecmd->rx_max_coalesced_frames; + vptr->options.tx_intsup = ecmd->tx_max_coalesced_frames; + + set_pending_timer_val(&vptr->options.rxqueue_timer, + ecmd->rx_coalesce_usecs); + set_pending_timer_val(&vptr->options.txqueue_timer, + ecmd->tx_coalesce_usecs); + + /* Setup the interrupt suppression and queue timers */ + mac_disable_int(vptr->mac_regs); + setup_adaptive_interrupts(vptr); + setup_queue_timers(vptr); + + mac_write_int_mask(vptr->int_mask, vptr->mac_regs); + mac_clear_isr(vptr->mac_regs); + mac_enable_int(vptr->mac_regs); + + return 0; +} + static const struct ethtool_ops velocity_ethtool_ops = { .get_settings = velocity_get_settings, .set_settings = velocity_set_settings, .get_drvinfo = velocity_get_drvinfo, + .set_tx_csum = ethtool_op_set_tx_csum, + .get_tx_csum = ethtool_op_get_tx_csum, .get_wol = velocity_ethtool_get_wol, .set_wol = velocity_ethtool_set_wol, .get_msglevel = velocity_get_msglevel, .set_msglevel = velocity_set_msglevel, + .set_sg = ethtool_op_set_sg, .get_link = velocity_get_link, + .get_coalesce = velocity_get_coalesce, + .set_coalesce = velocity_set_coalesce, .begin = velocity_ethtool_up, .complete = velocity_ethtool_down }; diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h index ce894ffa7c9..ef4a0f64ba1 100644 --- a/drivers/net/via-velocity.h +++ b/drivers/net/via-velocity.h @@ -29,9 +29,10 @@ #define VELOCITY_NAME "via-velocity" #define VELOCITY_FULL_DRV_NAM "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver" -#define VELOCITY_VERSION "1.14" +#define VELOCITY_VERSION "1.15" #define VELOCITY_IO_SIZE 256 +#define VELOCITY_NAPI_WEIGHT 64 #define PKT_BUF_SZ 1540 @@ -1005,7 +1006,8 @@ struct mac_regs { volatile __le32 RDBaseLo; /* 0x38 */ volatile __le16 RDIdx; /* 0x3C */ - volatile __le16 reserved_3E; + volatile u8 TQETMR; /* 0x3E, VT3216 and above only */ + volatile u8 RQETMR; /* 0x3F, VT3216 and above only */ volatile __le32 TDBaseLo[4]; /* 0x40 */ @@ -1421,7 +1423,6 @@ enum velocity_msg_level { */ #define VELOCITY_FLAGS_TAGGING 0x00000001UL -#define VELOCITY_FLAGS_TX_CSUM 0x00000002UL #define VELOCITY_FLAGS_RX_CSUM 0x00000004UL #define VELOCITY_FLAGS_IP_ALIGN 0x00000008UL #define VELOCITY_FLAGS_VAL_PKT_LEN 0x00000010UL @@ -1491,6 +1492,10 @@ struct velocity_opt { int rx_bandwidth_hi; int rx_bandwidth_lo; int rx_bandwidth_en; + int rxqueue_timer; + int txqueue_timer; + int tx_intsup; + int rx_intsup; u32 flags; }; @@ -1557,6 +1562,8 @@ struct velocity_info { u32 ticks; u8 rev_id; + + struct napi_struct napi; }; /** diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 74636c5c41f..c708ecc3cb2 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -428,8 +428,8 @@ again: /* Out of packets? */ if (received < budget) { napi_complete(napi); - if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq)) - && napi_schedule_prep(napi)) { + if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq)) && + napi_schedule_prep(napi)) { vi->rvq->vq_ops->disable_cb(vi->rvq); __napi_schedule(napi); goto again; @@ -890,9 +890,9 @@ static int virtnet_probe(struct virtio_device *vdev) INIT_DELAYED_WORK(&vi->refill, refill_work); /* If we can receive ANY GSO packets, we must allocate large ones. */ - if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) - || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) - || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN)) + if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) || + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN)) vi->big_packets = true; if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index a4c97e786ee..1ceb9d0f8b9 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -1780,8 +1780,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter) set_flag_le64(&devRead->misc.uptFeatures, UPT1_F_LRO); devRead->misc.maxNumRxSG = cpu_to_le16(1 + MAX_SKB_FRAGS); } - if ((adapter->netdev->features & NETIF_F_HW_VLAN_RX) - && adapter->vlan_grp) { + if ((adapter->netdev->features & NETIF_F_HW_VLAN_RX) && + adapter->vlan_grp) { set_flag_le64(&devRead->misc.uptFeatures, UPT1_F_RXVLAN); } diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index e21358e82c7..f1c4b2a1e86 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -2510,9 +2510,9 @@ static int vxge_add_isr(struct vxgedev *vdev) } /* Point to next vpath handler */ - if (((intr_idx + 1) % VXGE_HW_VPATH_MSIX_ACTIVE == 0) - && (vp_idx < (vdev->no_of_vpath - 1))) - vp_idx++; + if (((intr_idx + 1) % VXGE_HW_VPATH_MSIX_ACTIVE == 0) && + (vp_idx < (vdev->no_of_vpath - 1))) + vp_idx++; } intr_cnt = vdev->max_vpath_supported * 2; diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index 61ce754fa9d..2c012f4ce46 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c @@ -1963,14 +1963,14 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( val64 = readq(&vp_reg->asic_ntwk_vp_err_reg); if (((val64 & - VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT) && - (!(val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT) && + (!(val64 & VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK))) || ((val64 & - VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR) - && (!(val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR) && + (!(val64 & VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR) - ))) { + ))) { sw_stats->error_stats.network_sustained_fault++; writeq( @@ -1983,14 +1983,14 @@ enum vxge_hw_status __vxge_hw_vpath_alarm_process( } if (((val64 & - VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK) && - (!(val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK) && + (!(val64 & VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT))) || ((val64 & - VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR) - && (!(val64 & + VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_OK_OCCURR) && + (!(val64 & VXGE_HW_ASIC_NW_VP_ERR_REG_XMACJ_STN_FLT_OCCURR) - ))) { + ))) { sw_stats->error_stats.network_sustained_ok++; diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index cd8f04afed8..b36bf96eb50 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -907,6 +907,7 @@ static ssize_t cosa_write(struct file *file, current->state = TASK_RUNNING; chan->tx_status = 1; spin_unlock_irqrestore(&cosa->lock, flags); + up(&chan->wsem); return -ERESTARTSYS; } } diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 15d353f268b..421d0715310 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -77,7 +77,7 @@ static int dlci_header(struct sk_buff *skb, struct net_device *dev, dlp = netdev_priv(dev); hdr.control = FRAD_I_UI; - switch(type) + switch (type) { case ETH_P_IP: hdr.IP_NLPID = FRAD_P_IP; @@ -130,7 +130,7 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) dev->stats.rx_errors++; } else - switch(hdr->IP_NLPID) + switch (hdr->IP_NLPID) { case FRAD_P_PADDING: if (hdr->NLPID != FRAD_P_SNAP) @@ -208,7 +208,7 @@ static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, in if (!get) { - if(copy_from_user(&config, conf, sizeof(struct dlci_conf))) + if (copy_from_user(&config, conf, sizeof(struct dlci_conf))) return -EFAULT; if (config.flags & ~DLCI_VALID_FLAGS) return(-EINVAL); @@ -222,7 +222,7 @@ static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, in if (get) { - if(copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf))) + if (copy_to_user(conf, &dlp->config, sizeof(struct dlci_conf))) return -EFAULT; } @@ -238,7 +238,7 @@ static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) dlp = netdev_priv(dev); - switch(cmd) + switch (cmd) { case DLCI_GET_SLAVE: if (!*(short *)(dev->dev_addr)) @@ -417,7 +417,7 @@ static int dlci_ioctl(unsigned int cmd, void __user *arg) if (!capable(CAP_NET_ADMIN)) return(-EPERM); - if(copy_from_user(&add, arg, sizeof(struct dlci_add))) + if (copy_from_user(&add, arg, sizeof(struct dlci_add))) return -EFAULT; switch (cmd) @@ -426,7 +426,7 @@ static int dlci_ioctl(unsigned int cmd, void __user *arg) err = dlci_add(&add); if (!err) - if(copy_to_user(arg, &add, sizeof(struct dlci_add))) + if (copy_to_user(arg, &add, sizeof(struct dlci_add))) return -EFAULT; break; diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index beda387f2fc..9bc2e364915 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -1346,8 +1346,8 @@ do_bottom_half_tx(struct fst_card_info *card) dev = port_to_dev(port); while (!(FST_RDB(card, txDescrRing[pi][port->txpos].bits) & - DMA_OWN) - && !(card->dmatx_in_progress)) { + DMA_OWN) && + !(card->dmatx_in_progress)) { /* * There doesn't seem to be a txdone event per-se * We seem to have to deduce it, by checking the DMA_OWN @@ -1379,8 +1379,8 @@ do_bottom_half_tx(struct fst_card_info *card) */ FST_WRW(card, txDescrRing[pi][port->txpos].bcnt, cnv_bcnt(skb->len)); - if ((skb->len < FST_MIN_DMA_LEN) - || (card->family == FST_FAMILY_TXP)) { + if ((skb->len < FST_MIN_DMA_LEN) || + (card->family == FST_FAMILY_TXP)) { /* Enqueue the packet with normal io */ memcpy_toio(card->mem + BUF_OFFSET(txBuffer[pi] @@ -2030,8 +2030,8 @@ fst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Sanity check the parameters. We don't support partial writes * when going over the top */ - if (wrthdr.size > FST_MEMSIZE || wrthdr.offset > FST_MEMSIZE - || wrthdr.size + wrthdr.offset > FST_MEMSIZE) { + if (wrthdr.size > FST_MEMSIZE || wrthdr.offset > FST_MEMSIZE || + wrthdr.size + wrthdr.offset > FST_MEMSIZE) { return -ENXIO; } diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index cc07236ea73..9937bbab938 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -57,7 +57,7 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, { struct hdlc_device *hdlc = dev_to_hdlc(dev); - if (dev_net(dev) != &init_net) { + if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(skb); return 0; } @@ -102,7 +102,7 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event, unsigned long flags; int on; - if (dev_net(dev) != &init_net) + if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; if (!(dev->priv_flags & IFF_WAN_HDLC)) diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index 840cff72a0f..a7d4fc1a03a 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -1214,10 +1214,10 @@ static int fr_ioctl(struct net_device *dev, struct ifreq *ifr) return 0; case IF_PROTO_FR: - if(!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; - if(dev->flags & IFF_UP) + if (dev->flags & IFF_UP) return -EBUSY; if (copy_from_user(&new_settings, fr_s, size)) @@ -1263,7 +1263,7 @@ static int fr_ioctl(struct net_device *dev, struct ifreq *ifr) if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */ return -EINVAL; - if(!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&pvc, ifr->ifr_settings.ifs_ifsu.fr_pvc, diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 79dabc557bd..aec4d395542 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -514,8 +514,8 @@ static int dma_buf_read(pc300_t * card, int ch, struct sk_buff *skb) RX_BD_ADDR(ch, chan->rx_first_bd)); while ((status = cpc_readb(&ptdescr->status)) & DST_OSB) { nchar = cpc_readw(&ptdescr->len); - if ((status & (DST_OVR | DST_CRC | DST_RBIT | DST_SHRT | DST_ABT)) - || (nchar > BD_DEF_LEN)) { + if ((status & (DST_OVR | DST_CRC | DST_RBIT | DST_SHRT | DST_ABT)) || + (nchar > BD_DEF_LEN)) { if (nchar > BD_DEF_LEN) status |= DST_RBIT; @@ -1428,8 +1428,7 @@ static void falc_update_stats(pc300_t * card, int ch) if (((conf->media == IF_IFACE_T1) && (cpc_readb(falcbase + F_REG(FRS1, ch)) & FRS1_LLBAD) && - (!(cpc_readb(falcbase + F_REG(FRS1, ch)) & FRS1_PDEN))) - || + (!(cpc_readb(falcbase + F_REG(FRS1, ch)) & FRS1_PDEN))) || ((conf->media == IF_IFACE_E1) && (cpc_readb(falcbase + F_REG(RSP, ch)) & RSP_LLBAD))) { pfalc->prbs = 2; @@ -2285,8 +2284,8 @@ static void falc_e1_intr(pc300_t * card, int ch) if (gis & GIS_ISR1) { isr1 = cpc_readb(falcbase + F_REG(FISR1, ch)); if (isr1 & FISR1_XMB) { - if ((pfalc->xmb_cause & 2) - && pfalc->multiframe_mode) { + if ((pfalc->xmb_cause & 2) && + pfalc->multiframe_mode) { if (cpc_readb (falcbase + F_REG(FRS0, ch)) & (FRS0_LOS | FRS0_AIS | FRS0_LFA)) { cpc_writeb(falcbase + F_REG(XSP, ch), @@ -2639,9 +2638,9 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) !(cpc_readb (scabase + M_REG(CTL, ch)) & CTL_DTR); /* There is no DSR in HD64572 */ } - if (!arg - || copy_to_user(arg, &pc300status, sizeof(pc300status_t))) - return -EINVAL; + if (!arg || + copy_to_user(arg, &pc300status, sizeof(pc300status_t))) + return -EINVAL; return 0; } diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 1cc24a45f00..25477b5cde4 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -195,9 +195,9 @@ static unsigned int netcard_portlist[ ] __initdata = { static inline int __init sbni_isa_probe( struct net_device *dev ) { - if( dev->base_addr > 0x1ff - && request_region( dev->base_addr, SBNI_IO_EXTENT, dev->name ) - && sbni_probe1( dev, dev->base_addr, dev->irq ) ) + if( dev->base_addr > 0x1ff && + request_region( dev->base_addr, SBNI_IO_EXTENT, dev->name ) && + sbni_probe1( dev, dev->base_addr, dev->irq ) ) return 0; else { @@ -286,8 +286,8 @@ static int __init sbni_init(struct net_device *dev) for( i = 0; netcard_portlist[ i ]; ++i ) { int ioaddr = netcard_portlist[ i ]; - if( request_region( ioaddr, SBNI_IO_EXTENT, dev->name ) - && sbni_probe1( dev, ioaddr, 0 )) + if( request_region( ioaddr, SBNI_IO_EXTENT, dev->name ) && + sbni_probe1( dev, ioaddr, 0 )) return 0; } @@ -306,9 +306,9 @@ sbni_pci_probe( struct net_device *dev ) unsigned long pci_ioaddr; u16 subsys; - if( pdev->vendor != SBNI_PCI_VENDOR - && pdev->device != SBNI_PCI_DEVICE ) - continue; + if( pdev->vendor != SBNI_PCI_VENDOR && + pdev->device != SBNI_PCI_DEVICE ) + continue; pci_ioaddr = pci_resource_start( pdev, 0 ); pci_irq_line = pdev->irq; @@ -977,8 +977,8 @@ check_fhdr( u32 ioaddr, u32 *framelen, u32 *frameno, u32 *ack, *ack = *framelen & FRAME_ACK_MASK; *is_first = (*framelen & FRAME_FIRST) != 0; - if( (*framelen &= FRAME_LEN_MASK) < 6 - || *framelen > SBNI_MAX_FRAME - 3 ) + if( (*framelen &= FRAME_LEN_MASK) < 6 || + *framelen > SBNI_MAX_FRAME - 3 ) return 0; value = inb( ioaddr + DAT ); @@ -1173,10 +1173,10 @@ sbni_open( struct net_device *dev ) if( dev->base_addr < 0x400 ) { /* ISA only */ struct net_device **p = sbni_cards; for( ; *p && p < sbni_cards + SBNI_MAX_NUM_CARDS; ++p ) - if( (*p)->irq == dev->irq - && ((*p)->base_addr == dev->base_addr + 4 - || (*p)->base_addr == dev->base_addr - 4) - && (*p)->flags & IFF_UP ) { + if( (*p)->irq == dev->irq && + ((*p)->base_addr == dev->base_addr + 4 || + (*p)->base_addr == dev->base_addr - 4) && + (*p)->flags & IFF_UP ) { ((struct net_local *) (netdev_priv(*p))) ->second = dev; diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index 3b3ee05bc46..61249f489e3 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -84,8 +84,7 @@ static int sealevel_open(struct net_device *d) * Link layer up. */ - switch (unit) - { + switch (unit) { case 0: err = z8530_sync_dma_open(d, slvl->chan); break; @@ -133,8 +132,7 @@ static int sealevel_close(struct net_device *d) hdlc_close(d); netif_stop_queue(d); - switch (unit) - { + switch (unit) { case 0: z8530_sync_dma_close(d, slvl->chan); break; @@ -342,8 +340,7 @@ static void __exit slvl_shutdown(struct slvl_board *b) z8530_shutdown(&b->board); - for (u = 0; u < 2; u++) - { + for (u = 0; u < 2; u++) { struct net_device *d = b->dev[u].chan->netdevice; unregister_hdlc_device(d); free_netdev(d); @@ -391,7 +388,7 @@ static int __init slvl_init_module(void) static void __exit slvl_cleanup_module(void) { - if(slvl_unit) + if (slvl_unit) slvl_shutdown(slvl_unit); } diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 3c325d77939..b9f520b7db6 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -657,8 +657,8 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) switch (s) { case X25_END: - if (!test_and_clear_bit(SLF_ERROR, &sl->flags) - && sl->rcount > 2) + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && + sl->rcount > 2) x25_asy_bump(sl); clear_bit(SLF_ESCAPE, &sl->flags); sl->rcount = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 888a8e9fe9e..58b132f9cf2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -1350,8 +1350,16 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) return -ENXIO; } + if (priv->stations[sta_id].tid[tid].agg.state == + IWL_EMPTYING_HW_QUEUE_ADDBA) { + IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); + ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); + priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; + return 0; + } + if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON) - IWL_WARN(priv, "Stopping AGG while state not IWL_AGG_ON\n"); + IWL_WARN(priv, "Stopping AGG while state not ON or starting\n"); tid_data = &priv->stations[sta_id].tid[tid]; ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index d831dfca097..0f773a9a3ff 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -944,8 +944,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance) dev_kfree_skb_irq(skb); yp->tx_skbuff[entry] = NULL; } - if (yp->tx_full - && yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) { + if (yp->tx_full && + yp->cur_tx - yp->dirty_tx < TX_QUEUE_SIZE - 4) { /* The ring is no longer full, clear tbusy. */ yp->tx_full = 0; netif_wake_queue(dev); @@ -1014,8 +1014,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance) } #endif - if (yp->tx_full - && yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) { + if (yp->tx_full && + yp->cur_tx - dirty_tx < TX_QUEUE_SIZE - 2) { /* The ring is no longer full, clear tbusy. */ yp->tx_full = 0; netif_wake_queue(dev); diff --git a/drivers/net/znet.c b/drivers/net/znet.c index a97d894d26f..bc5ae0f6e93 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -697,8 +697,8 @@ static void znet_rx(struct net_device *dev) the same area of the backwards links we now have. This allows us to pass packets to the upper layers in the order they were received -- important for fast-path sequential operations. */ - while (znet->rx_start + cur_frame_end_offset != znet->rx_cur - && ++boguscount < 5) { + while (znet->rx_start + cur_frame_end_offset != znet->rx_cur && + ++boguscount < 5) { unsigned short hi_cnt, lo_cnt, hi_status, lo_status; int count, status; |