diff options
Diffstat (limited to 'drivers/net/ethernet/intel/e100.c')
| -rw-r--r-- | drivers/net/ethernet/intel/e100.c | 199 |
1 files changed, 146 insertions, 53 deletions
diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index 9436397e572..9d979d7debe 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -412,6 +412,10 @@ enum cb_status { cb_ok = 0x2000, }; +/** + * cb_command - Command Block flags + * @cb_tx_nc: 0: controler does CRC (normal), 1: CRC from skb memory + */ enum cb_command { cb_nop = 0x0000, cb_iaaddr = 0x0001, @@ -421,6 +425,7 @@ enum cb_command { cb_ucode = 0x0005, cb_dump = 0x0006, cb_tx_sf = 0x0008, + cb_tx_nc = 0x0010, cb_cid = 0x1f00, cb_i = 0x2000, cb_s = 0x4000, @@ -457,7 +462,7 @@ struct config { /*5*/ u8 X(tx_dma_max_count:7, dma_max_count_enable:1); /*6*/ u8 X(X(X(X(X(X(X(late_scb_update:1, direct_rx_dma:1), tno_intr:1), cna_intr:1), standard_tcb:1), standard_stat_counter:1), - rx_discard_overruns:1), rx_save_bad_frames:1); + rx_save_overruns : 1), rx_save_bad_frames : 1); /*7*/ u8 X(X(X(X(X(rx_discard_short_frames:1, tx_underrun_retry:2), pad7:2), rx_extended_rfd:1), tx_two_frames_in_fifo:1), tx_dynamic_tbd:1); @@ -617,6 +622,7 @@ struct nic { u32 rx_fc_pause; u32 rx_fc_unsupported; u32 rx_tco_frames; + u32 rx_short_frame_errors; u32 rx_over_length_errors; u16 eeprom_wc; @@ -864,7 +870,7 @@ err_unlock: } static int e100_exec_cb(struct nic *nic, struct sk_buff *skb, - void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) + int (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) { struct cb *cb; unsigned long flags; @@ -882,10 +888,13 @@ static int e100_exec_cb(struct nic *nic, struct sk_buff *skb, nic->cbs_avail--; cb->skb = skb; + err = cb_prepare(nic, cb, skb); + if (err) + goto err_unlock; + if (unlikely(!nic->cbs_avail)) err = -ENOSPC; - cb_prepare(nic, cb, skb); /* Order is important otherwise we'll be in a race with h/w: * set S-bit in current first, then clear S-bit in previous. */ @@ -1075,7 +1084,7 @@ static void e100_get_defaults(struct nic *nic) /* Template for a freshly allocated RFD */ nic->blank_rfd.command = 0; nic->blank_rfd.rbd = cpu_to_le32(0xFFFFFFFF); - nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); + nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN + ETH_FCS_LEN); /* MII setup */ nic->mii.phy_id_mask = 0x1F; @@ -1085,10 +1094,11 @@ static void e100_get_defaults(struct nic *nic) nic->mii.mdio_write = mdio_write; } -static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) +static int e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) { struct config *config = &cb->u.config; u8 *c = (u8 *)config; + struct net_device *netdev = nic->netdev; cb->command = cpu_to_le16(cb_config); @@ -1132,6 +1142,9 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) config->promiscuous_mode = 0x1; /* 1=on, 0=off */ } + if (unlikely(netdev->features & NETIF_F_RXFCS)) + config->rx_crc_transfer = 0x1; /* 1=save, 0=discard */ + if (nic->flags & multicast_all) config->multicast_all = 0x1; /* 1=accept, 0=no */ @@ -1156,15 +1169,19 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) } } - netif_printk(nic, hw, KERN_DEBUG, nic->netdev, - "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); - netif_printk(nic, hw, KERN_DEBUG, nic->netdev, - "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]); - netif_printk(nic, hw, KERN_DEBUG, nic->netdev, - "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", - c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]); + if (netdev->features & NETIF_F_RXALL) { + config->rx_save_overruns = 0x1; /* 1=save, 0=discard */ + config->rx_save_bad_frames = 0x1; /* 1=save, 0=discard */ + config->rx_discard_short_frames = 0x0; /* 1=discard, 0=save */ + } + + netif_printk(nic, hw, KERN_DEBUG, nic->netdev, "[00-07]=%8ph\n", + c + 0); + netif_printk(nic, hw, KERN_DEBUG, nic->netdev, "[08-15]=%8ph\n", + c + 8); + netif_printk(nic, hw, KERN_DEBUG, nic->netdev, "[16-23]=%8ph\n", + c + 16); + return 0; } /************************************************************************* @@ -1233,20 +1250,35 @@ static const struct firmware *e100_request_firmware(struct nic *nic) const struct firmware *fw = nic->fw; u8 timer, bundle, min_size; int err = 0; + bool required = false; /* do not load u-code for ICH devices */ if (nic->flags & ich) return NULL; - /* Search for ucode match against h/w revision */ - if (nic->mac == mac_82559_D101M) + /* Search for ucode match against h/w revision + * + * Based on comments in the source code for the FreeBSD fxp + * driver, the FIRMWARE_D102E ucode includes both CPUSaver and + * + * "fixes for bugs in the B-step hardware (specifically, bugs + * with Inline Receive)." + * + * So we must fail if it cannot be loaded. + * + * The other microcode files are only required for the optional + * CPUSaver feature. Nice to have, but no reason to fail. + */ + if (nic->mac == mac_82559_D101M) { fw_name = FIRMWARE_D101M; - else if (nic->mac == mac_82559_D101S) + } else if (nic->mac == mac_82559_D101S) { fw_name = FIRMWARE_D101S; - else if (nic->mac == mac_82551_F || nic->mac == mac_82551_10) + } else if (nic->mac == mac_82551_F || nic->mac == mac_82551_10) { fw_name = FIRMWARE_D102E; - else /* No ucode on other devices */ + required = true; + } else { /* No ucode on other devices */ return NULL; + } /* If the firmware has not previously been loaded, request a pointer * to it. If it was previously loaded, we are reinitializing the @@ -1257,10 +1289,17 @@ static const struct firmware *e100_request_firmware(struct nic *nic) err = request_firmware(&fw, fw_name, &nic->pdev->dev); if (err) { - netif_err(nic, probe, nic->netdev, - "Failed to load firmware \"%s\": %d\n", - fw_name, err); - return ERR_PTR(err); + if (required) { + netif_err(nic, probe, nic->netdev, + "Failed to load firmware \"%s\": %d\n", + fw_name, err); + return ERR_PTR(err); + } else { + netif_info(nic, probe, nic->netdev, + "CPUSaver disabled. Needs \"%s\": %d\n", + fw_name, err); + return NULL; + } } /* Firmware should be precisely UCODE_SIZE (words) plus three bytes @@ -1293,7 +1332,7 @@ static const struct firmware *e100_request_firmware(struct nic *nic) return fw; } -static void e100_setup_ucode(struct nic *nic, struct cb *cb, +static int e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb) { const struct firmware *fw = (void *)skb; @@ -1320,6 +1359,7 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, cb->u.ucode[min_size] |= cpu_to_le32((BUNDLESMALL) ? 0xFFFF : 0xFF80); cb->command = cpu_to_le16(cb_ucode | cb_el); + return 0; } static inline int e100_load_ucode_wait(struct nic *nic) @@ -1362,18 +1402,20 @@ static inline int e100_load_ucode_wait(struct nic *nic) return err; } -static void e100_setup_iaaddr(struct nic *nic, struct cb *cb, +static int e100_setup_iaaddr(struct nic *nic, struct cb *cb, struct sk_buff *skb) { cb->command = cpu_to_le16(cb_iaaddr); memcpy(cb->u.iaaddr, nic->netdev->dev_addr, ETH_ALEN); + return 0; } -static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb) +static int e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb) { cb->command = cpu_to_le16(cb_dump); cb->u.dump_buffer_addr = cpu_to_le32(nic->dma_addr + offsetof(struct mem, dump_buf)); + return 0; } static int e100_phy_check_without_mii(struct nic *nic) @@ -1543,7 +1585,7 @@ static int e100_hw_init(struct nic *nic) return 0; } -static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb) +static int e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb) { struct net_device *netdev = nic->netdev; struct netdev_hw_addr *ha; @@ -1558,6 +1600,7 @@ static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb) memcpy(&cb->u.multi.addr[i++ * ETH_ALEN], &ha->addr, ETH_ALEN); } + return 0; } static void e100_set_multicast_list(struct net_device *netdev) @@ -1607,7 +1650,9 @@ static void e100_update_stats(struct nic *nic) ns->collisions += nic->tx_collisions; ns->tx_errors += le32_to_cpu(s->tx_max_collisions) + le32_to_cpu(s->tx_lost_crs); - ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors) + + nic->rx_short_frame_errors += + le32_to_cpu(s->rx_short_frame_errors); + ns->rx_length_errors = nic->rx_short_frame_errors + nic->rx_over_length_errors; ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors); ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors); @@ -1716,10 +1761,27 @@ static void e100_watchdog(unsigned long data) round_jiffies(jiffies + E100_WATCHDOG_PERIOD)); } -static void e100_xmit_prepare(struct nic *nic, struct cb *cb, +static int e100_xmit_prepare(struct nic *nic, struct cb *cb, struct sk_buff *skb) { + dma_addr_t dma_addr; cb->command = nic->tx_command; + + dma_addr = pci_map_single(nic->pdev, + skb->data, skb->len, PCI_DMA_TODEVICE); + /* If we can't map the skb, have the upper layer try later */ + if (pci_dma_mapping_error(nic->pdev, dma_addr)) + return -ENOMEM; + + /* + * Use the last 4 bytes of the SKB payload packet as the CRC, used for + * testing, ie sending frames with bad CRC. + */ + if (unlikely(skb->no_fcs)) + cb->command |= cpu_to_le16(cb_tx_nc); + else + cb->command &= ~cpu_to_le16(cb_tx_nc); + /* interrupt every 16 packets regardless of delay */ if ((nic->cbs_avail & ~15) == nic->cbs_avail) cb->command |= cpu_to_le16(cb_i); @@ -1727,10 +1789,10 @@ static void e100_xmit_prepare(struct nic *nic, struct cb *cb, cb->u.tcb.tcb_byte_count = 0; cb->u.tcb.threshold = nic->tx_threshold; cb->u.tcb.tbd_count = 1; - cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev, - skb->data, skb->len, PCI_DMA_TODEVICE)); - /* check for mapping failure? */ + cb->u.tcb.tbd.buf_addr = cpu_to_le32(dma_addr); cb->u.tcb.tbd.size = cpu_to_le16(skb->len); + skb_tx_timestamp(skb); + return 0; } static netdev_tx_t e100_xmit_frame(struct sk_buff *skb, @@ -1881,7 +1943,7 @@ static inline void e100_start_receiver(struct nic *nic, struct rx *rx) } } -#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) +#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN + ETH_FCS_LEN) static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) { if (!(rx->skb = netdev_alloc_skb_ip_align(nic->netdev, RFD_BUF_LEN))) @@ -1919,6 +1981,7 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, struct sk_buff *skb = rx->skb; struct rfd *rfd = (struct rfd *)skb->data; u16 rfd_status, actual_size; + u16 fcs_pad = 0; if (unlikely(work_done && *work_done >= work_to_do)) return -EAGAIN; @@ -1951,6 +2014,8 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, } /* Get actual data size */ + if (unlikely(dev->features & NETIF_F_RXFCS)) + fcs_pad = 4; actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF; if (unlikely(actual_size > RFD_BUF_LEN - sizeof(struct rfd))) actual_size = RFD_BUF_LEN - sizeof(struct rfd); @@ -1977,16 +2042,27 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, skb_put(skb, actual_size); skb->protocol = eth_type_trans(skb, nic->netdev); + /* If we are receiving all frames, then don't bother + * checking for errors. + */ + if (unlikely(dev->features & NETIF_F_RXALL)) { + if (actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN + fcs_pad) + /* Received oversized frame, but keep it. */ + nic->rx_over_length_errors++; + goto process_skb; + } + if (unlikely(!(rfd_status & cb_ok))) { /* Don't indicate if hardware indicates errors */ dev_kfree_skb_any(skb); - } else if (actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) { + } else if (actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN + fcs_pad) { /* Don't indicate oversized frames */ nic->rx_over_length_errors++; dev_kfree_skb_any(skb); } else { +process_skb: dev->stats.rx_packets++; - dev->stats.rx_bytes += actual_size; + dev->stats.rx_bytes += (actual_size - fcs_pad); netif_receive_skb(skb); if (work_done) (*work_done)++; @@ -2058,7 +2134,8 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done, pci_dma_sync_single_for_device(nic->pdev, old_before_last_rx->dma_addr, sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL); - old_before_last_rfd->size = cpu_to_le16(VLAN_ETH_FRAME_LEN); + old_before_last_rfd->size = cpu_to_le16(VLAN_ETH_FRAME_LEN + + ETH_FCS_LEN); pci_dma_sync_single_for_device(nic->pdev, old_before_last_rx->dma_addr, sizeof(struct rfd), PCI_DMA_BIDIRECTIONAL); @@ -2618,6 +2695,7 @@ static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = { "tx_deferred", "tx_single_collisions", "tx_multi_collisions", "tx_flow_control_pause", "rx_flow_control_pause", "rx_flow_control_unsupported", "tx_tco_packets", "rx_tco_packets", + "rx_short_frame_errors", "rx_over_length_errors", }; #define E100_NET_STATS_LEN 21 #define E100_STATS_LEN ARRAY_SIZE(e100_gstrings_stats) @@ -2651,6 +2729,8 @@ static void e100_get_ethtool_stats(struct net_device *netdev, data[i++] = nic->rx_fc_unsupported; data[i++] = nic->tx_tco_frames; data[i++] = nic->rx_tco_frames; + data[i++] = nic->rx_short_frame_errors; + data[i++] = nic->rx_over_length_errors; } static void e100_get_strings(struct net_device *netdev, u32 stringset, u8 *data) @@ -2687,6 +2767,7 @@ static const struct ethtool_ops e100_ethtool_ops = { .set_phys_id = e100_set_phys_id, .get_ethtool_stats = e100_get_ethtool_stats, .get_sset_count = e100_get_sset_count, + .get_ts_info = ethtool_op_get_ts_info, }; static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) @@ -2729,6 +2810,20 @@ static int e100_close(struct net_device *netdev) return 0; } +static int e100_set_features(struct net_device *netdev, + netdev_features_t features) +{ + struct nic *nic = netdev_priv(netdev); + netdev_features_t changed = features ^ netdev->features; + + if (!(changed & (NETIF_F_RXFCS | NETIF_F_RXALL))) + return 0; + + netdev->features = features; + e100_exec_cb(nic, NULL, e100_configure); + return 0; +} + static const struct net_device_ops e100_netdev_ops = { .ndo_open = e100_open, .ndo_stop = e100_close, @@ -2742,23 +2837,24 @@ static const struct net_device_ops e100_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = e100_netpoll, #endif + .ndo_set_features = e100_set_features, }; -static int __devinit e100_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) +static int e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct nic *nic; int err; - if (!(netdev = alloc_etherdev(sizeof(struct nic)))) { - if (((1 << debug) - 1) & NETIF_MSG_PROBE) - pr_err("Etherdev alloc failed, aborting\n"); + if (!(netdev = alloc_etherdev(sizeof(struct nic)))) return -ENOMEM; - } + + netdev->hw_features |= NETIF_F_RXFCS; + netdev->priv_flags |= IFF_SUPP_NOFCS; + netdev->hw_features |= NETIF_F_RXALL; netdev->netdev_ops = &e100_netdev_ops; - SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); + netdev->ethtool_ops = &e100_ethtool_ops; netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); @@ -2843,8 +2939,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, e100_phy_init(nic); memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN); - memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN); - if (!is_valid_ether_addr(netdev->perm_addr)) { + if (!is_valid_ether_addr(netdev->dev_addr)) { if (!eeprom_bad_csum_allow) { netif_err(nic, probe, nic->netdev, "Invalid MAC address from EEPROM, aborting\n"); err = -EAGAIN; @@ -2890,12 +2985,11 @@ err_out_free_res: err_out_disable_pdev: pci_disable_device(pdev); err_out_free_dev: - pci_set_drvdata(pdev, NULL); free_netdev(netdev); return err; } -static void __devexit e100_remove(struct pci_dev *pdev) +static void e100_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); @@ -2908,7 +3002,6 @@ static void __devexit e100_remove(struct pci_dev *pdev) free_netdev(netdev); pci_release_regions(pdev); pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); } } @@ -2941,7 +3034,7 @@ static void __e100_shutdown(struct pci_dev *pdev, bool *enable_wake) *enable_wake = false; } - pci_disable_device(pdev); + pci_clear_master(pdev); } static int __e100_power_off(struct pci_dev *pdev, bool wake) @@ -2971,7 +3064,7 @@ static int e100_resume(struct pci_dev *pdev) pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); /* ack any pending wake events, disable PME */ - pci_enable_wake(pdev, 0, 0); + pci_enable_wake(pdev, PCI_D0, 0); /* disable reverse auto-negotiation */ if (nic->phy == phy_82552_v) { @@ -3062,7 +3155,7 @@ static void e100_io_resume(struct pci_dev *pdev) struct nic *nic = netdev_priv(netdev); /* ack any pending wake events, disable PME */ - pci_enable_wake(pdev, 0, 0); + pci_enable_wake(pdev, PCI_D0, 0); netif_device_attach(netdev); if (netif_running(netdev)) { @@ -3071,7 +3164,7 @@ static void e100_io_resume(struct pci_dev *pdev) } } -static struct pci_error_handlers e100_err_handler = { +static const struct pci_error_handlers e100_err_handler = { .error_detected = e100_io_error_detected, .slot_reset = e100_io_slot_reset, .resume = e100_io_resume, @@ -3081,7 +3174,7 @@ static struct pci_driver e100_driver = { .name = DRV_NAME, .id_table = e100_id_table, .probe = e100_probe, - .remove = __devexit_p(e100_remove), + .remove = e100_remove, #ifdef CONFIG_PM /* Power Management hooks */ .suspend = e100_suspend, |
