0001
0002 #include <linux/kernel.h>
0003 #include <linux/types.h>
0004 #include <linux/module.h>
0005 #include <linux/list.h>
0006 #include <linux/pci.h>
0007 #include <linux/dma-mapping.h>
0008 #include <linux/pagemap.h>
0009 #include <linux/sched.h>
0010 #include <linux/dmapool.h>
0011 #include <linux/mempool.h>
0012 #include <linux/spinlock.h>
0013 #include <linux/kthread.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/errno.h>
0016 #include <linux/ioport.h>
0017 #include <linux/in.h>
0018 #include <linux/ip.h>
0019 #include <linux/ipv6.h>
0020 #include <net/ipv6.h>
0021 #include <linux/tcp.h>
0022 #include <linux/udp.h>
0023 #include <linux/if_arp.h>
0024 #include <linux/if_ether.h>
0025 #include <linux/netdevice.h>
0026 #include <linux/etherdevice.h>
0027 #include <linux/ethtool.h>
0028 #include <linux/skbuff.h>
0029 #include <linux/rtnetlink.h>
0030 #include <linux/if_vlan.h>
0031 #include <linux/delay.h>
0032 #include <linux/mm.h>
0033 #include <linux/vmalloc.h>
0034
0035 #include "qlge.h"
0036
0037 struct qlge_stats {
0038 char stat_string[ETH_GSTRING_LEN];
0039 int sizeof_stat;
0040 int stat_offset;
0041 };
0042
0043 #define QL_SIZEOF(m) sizeof_field(struct qlge_adapter, m)
0044 #define QL_OFF(m) offsetof(struct qlge_adapter, m)
0045
0046 static const struct qlge_stats qlge_gstrings_stats[] = {
0047 {"tx_pkts", QL_SIZEOF(nic_stats.tx_pkts), QL_OFF(nic_stats.tx_pkts)},
0048 {"tx_bytes", QL_SIZEOF(nic_stats.tx_bytes), QL_OFF(nic_stats.tx_bytes)},
0049 {"tx_mcast_pkts", QL_SIZEOF(nic_stats.tx_mcast_pkts),
0050 QL_OFF(nic_stats.tx_mcast_pkts)},
0051 {"tx_bcast_pkts", QL_SIZEOF(nic_stats.tx_bcast_pkts),
0052 QL_OFF(nic_stats.tx_bcast_pkts)},
0053 {"tx_ucast_pkts", QL_SIZEOF(nic_stats.tx_ucast_pkts),
0054 QL_OFF(nic_stats.tx_ucast_pkts)},
0055 {"tx_ctl_pkts", QL_SIZEOF(nic_stats.tx_ctl_pkts),
0056 QL_OFF(nic_stats.tx_ctl_pkts)},
0057 {"tx_pause_pkts", QL_SIZEOF(nic_stats.tx_pause_pkts),
0058 QL_OFF(nic_stats.tx_pause_pkts)},
0059 {"tx_64_pkts", QL_SIZEOF(nic_stats.tx_64_pkt),
0060 QL_OFF(nic_stats.tx_64_pkt)},
0061 {"tx_65_to_127_pkts", QL_SIZEOF(nic_stats.tx_65_to_127_pkt),
0062 QL_OFF(nic_stats.tx_65_to_127_pkt)},
0063 {"tx_128_to_255_pkts", QL_SIZEOF(nic_stats.tx_128_to_255_pkt),
0064 QL_OFF(nic_stats.tx_128_to_255_pkt)},
0065 {"tx_256_511_pkts", QL_SIZEOF(nic_stats.tx_256_511_pkt),
0066 QL_OFF(nic_stats.tx_256_511_pkt)},
0067 {"tx_512_to_1023_pkts", QL_SIZEOF(nic_stats.tx_512_to_1023_pkt),
0068 QL_OFF(nic_stats.tx_512_to_1023_pkt)},
0069 {"tx_1024_to_1518_pkts", QL_SIZEOF(nic_stats.tx_1024_to_1518_pkt),
0070 QL_OFF(nic_stats.tx_1024_to_1518_pkt)},
0071 {"tx_1519_to_max_pkts", QL_SIZEOF(nic_stats.tx_1519_to_max_pkt),
0072 QL_OFF(nic_stats.tx_1519_to_max_pkt)},
0073 {"tx_undersize_pkts", QL_SIZEOF(nic_stats.tx_undersize_pkt),
0074 QL_OFF(nic_stats.tx_undersize_pkt)},
0075 {"tx_oversize_pkts", QL_SIZEOF(nic_stats.tx_oversize_pkt),
0076 QL_OFF(nic_stats.tx_oversize_pkt)},
0077 {"rx_bytes", QL_SIZEOF(nic_stats.rx_bytes), QL_OFF(nic_stats.rx_bytes)},
0078 {"rx_bytes_ok", QL_SIZEOF(nic_stats.rx_bytes_ok),
0079 QL_OFF(nic_stats.rx_bytes_ok)},
0080 {"rx_pkts", QL_SIZEOF(nic_stats.rx_pkts), QL_OFF(nic_stats.rx_pkts)},
0081 {"rx_pkts_ok", QL_SIZEOF(nic_stats.rx_pkts_ok),
0082 QL_OFF(nic_stats.rx_pkts_ok)},
0083 {"rx_bcast_pkts", QL_SIZEOF(nic_stats.rx_bcast_pkts),
0084 QL_OFF(nic_stats.rx_bcast_pkts)},
0085 {"rx_mcast_pkts", QL_SIZEOF(nic_stats.rx_mcast_pkts),
0086 QL_OFF(nic_stats.rx_mcast_pkts)},
0087 {"rx_ucast_pkts", QL_SIZEOF(nic_stats.rx_ucast_pkts),
0088 QL_OFF(nic_stats.rx_ucast_pkts)},
0089 {"rx_undersize_pkts", QL_SIZEOF(nic_stats.rx_undersize_pkts),
0090 QL_OFF(nic_stats.rx_undersize_pkts)},
0091 {"rx_oversize_pkts", QL_SIZEOF(nic_stats.rx_oversize_pkts),
0092 QL_OFF(nic_stats.rx_oversize_pkts)},
0093 {"rx_jabber_pkts", QL_SIZEOF(nic_stats.rx_jabber_pkts),
0094 QL_OFF(nic_stats.rx_jabber_pkts)},
0095 {"rx_undersize_fcerr_pkts",
0096 QL_SIZEOF(nic_stats.rx_undersize_fcerr_pkts),
0097 QL_OFF(nic_stats.rx_undersize_fcerr_pkts)},
0098 {"rx_drop_events", QL_SIZEOF(nic_stats.rx_drop_events),
0099 QL_OFF(nic_stats.rx_drop_events)},
0100 {"rx_fcerr_pkts", QL_SIZEOF(nic_stats.rx_fcerr_pkts),
0101 QL_OFF(nic_stats.rx_fcerr_pkts)},
0102 {"rx_align_err", QL_SIZEOF(nic_stats.rx_align_err),
0103 QL_OFF(nic_stats.rx_align_err)},
0104 {"rx_symbol_err", QL_SIZEOF(nic_stats.rx_symbol_err),
0105 QL_OFF(nic_stats.rx_symbol_err)},
0106 {"rx_mac_err", QL_SIZEOF(nic_stats.rx_mac_err),
0107 QL_OFF(nic_stats.rx_mac_err)},
0108 {"rx_ctl_pkts", QL_SIZEOF(nic_stats.rx_ctl_pkts),
0109 QL_OFF(nic_stats.rx_ctl_pkts)},
0110 {"rx_pause_pkts", QL_SIZEOF(nic_stats.rx_pause_pkts),
0111 QL_OFF(nic_stats.rx_pause_pkts)},
0112 {"rx_64_pkts", QL_SIZEOF(nic_stats.rx_64_pkts),
0113 QL_OFF(nic_stats.rx_64_pkts)},
0114 {"rx_65_to_127_pkts", QL_SIZEOF(nic_stats.rx_65_to_127_pkts),
0115 QL_OFF(nic_stats.rx_65_to_127_pkts)},
0116 {"rx_128_255_pkts", QL_SIZEOF(nic_stats.rx_128_255_pkts),
0117 QL_OFF(nic_stats.rx_128_255_pkts)},
0118 {"rx_256_511_pkts", QL_SIZEOF(nic_stats.rx_256_511_pkts),
0119 QL_OFF(nic_stats.rx_256_511_pkts)},
0120 {"rx_512_to_1023_pkts", QL_SIZEOF(nic_stats.rx_512_to_1023_pkts),
0121 QL_OFF(nic_stats.rx_512_to_1023_pkts)},
0122 {"rx_1024_to_1518_pkts", QL_SIZEOF(nic_stats.rx_1024_to_1518_pkts),
0123 QL_OFF(nic_stats.rx_1024_to_1518_pkts)},
0124 {"rx_1519_to_max_pkts", QL_SIZEOF(nic_stats.rx_1519_to_max_pkts),
0125 QL_OFF(nic_stats.rx_1519_to_max_pkts)},
0126 {"rx_len_err_pkts", QL_SIZEOF(nic_stats.rx_len_err_pkts),
0127 QL_OFF(nic_stats.rx_len_err_pkts)},
0128 {"rx_code_err", QL_SIZEOF(nic_stats.rx_code_err),
0129 QL_OFF(nic_stats.rx_code_err)},
0130 {"rx_oversize_err", QL_SIZEOF(nic_stats.rx_oversize_err),
0131 QL_OFF(nic_stats.rx_oversize_err)},
0132 {"rx_undersize_err", QL_SIZEOF(nic_stats.rx_undersize_err),
0133 QL_OFF(nic_stats.rx_undersize_err)},
0134 {"rx_preamble_err", QL_SIZEOF(nic_stats.rx_preamble_err),
0135 QL_OFF(nic_stats.rx_preamble_err)},
0136 {"rx_frame_len_err", QL_SIZEOF(nic_stats.rx_frame_len_err),
0137 QL_OFF(nic_stats.rx_frame_len_err)},
0138 {"rx_crc_err", QL_SIZEOF(nic_stats.rx_crc_err),
0139 QL_OFF(nic_stats.rx_crc_err)},
0140 {"rx_err_count", QL_SIZEOF(nic_stats.rx_err_count),
0141 QL_OFF(nic_stats.rx_err_count)},
0142 {"tx_cbfc_pause_frames0", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames0),
0143 QL_OFF(nic_stats.tx_cbfc_pause_frames0)},
0144 {"tx_cbfc_pause_frames1", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames1),
0145 QL_OFF(nic_stats.tx_cbfc_pause_frames1)},
0146 {"tx_cbfc_pause_frames2", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames2),
0147 QL_OFF(nic_stats.tx_cbfc_pause_frames2)},
0148 {"tx_cbfc_pause_frames3", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames3),
0149 QL_OFF(nic_stats.tx_cbfc_pause_frames3)},
0150 {"tx_cbfc_pause_frames4", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames4),
0151 QL_OFF(nic_stats.tx_cbfc_pause_frames4)},
0152 {"tx_cbfc_pause_frames5", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames5),
0153 QL_OFF(nic_stats.tx_cbfc_pause_frames5)},
0154 {"tx_cbfc_pause_frames6", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames6),
0155 QL_OFF(nic_stats.tx_cbfc_pause_frames6)},
0156 {"tx_cbfc_pause_frames7", QL_SIZEOF(nic_stats.tx_cbfc_pause_frames7),
0157 QL_OFF(nic_stats.tx_cbfc_pause_frames7)},
0158 {"rx_cbfc_pause_frames0", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames0),
0159 QL_OFF(nic_stats.rx_cbfc_pause_frames0)},
0160 {"rx_cbfc_pause_frames1", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames1),
0161 QL_OFF(nic_stats.rx_cbfc_pause_frames1)},
0162 {"rx_cbfc_pause_frames2", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames2),
0163 QL_OFF(nic_stats.rx_cbfc_pause_frames2)},
0164 {"rx_cbfc_pause_frames3", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames3),
0165 QL_OFF(nic_stats.rx_cbfc_pause_frames3)},
0166 {"rx_cbfc_pause_frames4", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames4),
0167 QL_OFF(nic_stats.rx_cbfc_pause_frames4)},
0168 {"rx_cbfc_pause_frames5", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames5),
0169 QL_OFF(nic_stats.rx_cbfc_pause_frames5)},
0170 {"rx_cbfc_pause_frames6", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames6),
0171 QL_OFF(nic_stats.rx_cbfc_pause_frames6)},
0172 {"rx_cbfc_pause_frames7", QL_SIZEOF(nic_stats.rx_cbfc_pause_frames7),
0173 QL_OFF(nic_stats.rx_cbfc_pause_frames7)},
0174 {"rx_nic_fifo_drop", QL_SIZEOF(nic_stats.rx_nic_fifo_drop),
0175 QL_OFF(nic_stats.rx_nic_fifo_drop)},
0176 };
0177
0178 static const char qlge_gstrings_test[][ETH_GSTRING_LEN] = {
0179 "Loopback test (offline)"
0180 };
0181
0182 #define QLGE_TEST_LEN (sizeof(qlge_gstrings_test) / ETH_GSTRING_LEN)
0183 #define QLGE_STATS_LEN ARRAY_SIZE(qlge_gstrings_stats)
0184 #define QLGE_RCV_MAC_ERR_STATS 7
0185
0186 static int qlge_update_ring_coalescing(struct qlge_adapter *qdev)
0187 {
0188 int i, status = 0;
0189 struct rx_ring *rx_ring;
0190 struct cqicb *cqicb;
0191
0192 if (!netif_running(qdev->ndev))
0193 return status;
0194
0195
0196
0197
0198 cqicb = (struct cqicb *)&qdev->rx_ring[qdev->rss_ring_count];
0199 if (le16_to_cpu(cqicb->irq_delay) != qdev->tx_coalesce_usecs ||
0200 le16_to_cpu(cqicb->pkt_delay) != qdev->tx_max_coalesced_frames) {
0201 for (i = qdev->rss_ring_count; i < qdev->rx_ring_count; i++) {
0202 rx_ring = &qdev->rx_ring[i];
0203 cqicb = (struct cqicb *)rx_ring;
0204 cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs);
0205 cqicb->pkt_delay =
0206 cpu_to_le16(qdev->tx_max_coalesced_frames);
0207 cqicb->flags = FLAGS_LI;
0208 status = qlge_write_cfg(qdev, cqicb, sizeof(*cqicb),
0209 CFG_LCQ, rx_ring->cq_id);
0210 if (status) {
0211 netif_err(qdev, ifup, qdev->ndev,
0212 "Failed to load CQICB.\n");
0213 goto exit;
0214 }
0215 }
0216 }
0217
0218
0219 cqicb = (struct cqicb *)&qdev->rx_ring[0];
0220 if (le16_to_cpu(cqicb->irq_delay) != qdev->rx_coalesce_usecs ||
0221 le16_to_cpu(cqicb->pkt_delay) != qdev->rx_max_coalesced_frames) {
0222 for (i = 0; i < qdev->rss_ring_count; i++, rx_ring++) {
0223 rx_ring = &qdev->rx_ring[i];
0224 cqicb = (struct cqicb *)rx_ring;
0225 cqicb->irq_delay = cpu_to_le16(qdev->rx_coalesce_usecs);
0226 cqicb->pkt_delay =
0227 cpu_to_le16(qdev->rx_max_coalesced_frames);
0228 cqicb->flags = FLAGS_LI;
0229 status = qlge_write_cfg(qdev, cqicb, sizeof(*cqicb),
0230 CFG_LCQ, rx_ring->cq_id);
0231 if (status) {
0232 netif_err(qdev, ifup, qdev->ndev,
0233 "Failed to load CQICB.\n");
0234 goto exit;
0235 }
0236 }
0237 }
0238 exit:
0239 return status;
0240 }
0241
0242 static void qlge_update_stats(struct qlge_adapter *qdev)
0243 {
0244 u32 i;
0245 u64 data;
0246 u64 *iter = &qdev->nic_stats.tx_pkts;
0247
0248 spin_lock(&qdev->stats_lock);
0249 if (qlge_sem_spinlock(qdev, qdev->xg_sem_mask)) {
0250 netif_err(qdev, drv, qdev->ndev,
0251 "Couldn't get xgmac sem.\n");
0252 goto quit;
0253 }
0254
0255
0256
0257 for (i = 0x200; i < 0x280; i += 8) {
0258 if (qlge_read_xgmac_reg64(qdev, i, &data)) {
0259 netif_err(qdev, drv, qdev->ndev,
0260 "Error reading status register 0x%.04x.\n",
0261 i);
0262 goto end;
0263 } else {
0264 *iter = data;
0265 }
0266 iter++;
0267 }
0268
0269
0270
0271
0272 for (i = 0x300; i < 0x3d0; i += 8) {
0273 if (qlge_read_xgmac_reg64(qdev, i, &data)) {
0274 netif_err(qdev, drv, qdev->ndev,
0275 "Error reading status register 0x%.04x.\n",
0276 i);
0277 goto end;
0278 } else {
0279 *iter = data;
0280 }
0281 iter++;
0282 }
0283
0284
0285 iter += QLGE_RCV_MAC_ERR_STATS;
0286
0287
0288
0289
0290 for (i = 0x500; i < 0x540; i += 8) {
0291 if (qlge_read_xgmac_reg64(qdev, i, &data)) {
0292 netif_err(qdev, drv, qdev->ndev,
0293 "Error reading status register 0x%.04x.\n",
0294 i);
0295 goto end;
0296 } else {
0297 *iter = data;
0298 }
0299 iter++;
0300 }
0301
0302
0303
0304
0305 for (i = 0x568; i < 0x5a8; i += 8) {
0306 if (qlge_read_xgmac_reg64(qdev, i, &data)) {
0307 netif_err(qdev, drv, qdev->ndev,
0308 "Error reading status register 0x%.04x.\n",
0309 i);
0310 goto end;
0311 } else {
0312 *iter = data;
0313 }
0314 iter++;
0315 }
0316
0317
0318
0319
0320 if (qlge_read_xgmac_reg64(qdev, 0x5b8, &data)) {
0321 netif_err(qdev, drv, qdev->ndev,
0322 "Error reading status register 0x%.04x.\n", i);
0323 goto end;
0324 } else {
0325 *iter = data;
0326 }
0327 end:
0328 qlge_sem_unlock(qdev, qdev->xg_sem_mask);
0329 quit:
0330 spin_unlock(&qdev->stats_lock);
0331 }
0332
0333 static void qlge_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
0334 {
0335 int index;
0336
0337 switch (stringset) {
0338 case ETH_SS_TEST:
0339 memcpy(buf, *qlge_gstrings_test, QLGE_TEST_LEN * ETH_GSTRING_LEN);
0340 break;
0341 case ETH_SS_STATS:
0342 for (index = 0; index < QLGE_STATS_LEN; index++) {
0343 memcpy(buf + index * ETH_GSTRING_LEN,
0344 qlge_gstrings_stats[index].stat_string,
0345 ETH_GSTRING_LEN);
0346 }
0347 break;
0348 }
0349 }
0350
0351 static int qlge_get_sset_count(struct net_device *dev, int sset)
0352 {
0353 switch (sset) {
0354 case ETH_SS_TEST:
0355 return QLGE_TEST_LEN;
0356 case ETH_SS_STATS:
0357 return QLGE_STATS_LEN;
0358 default:
0359 return -EOPNOTSUPP;
0360 }
0361 }
0362
0363 static void
0364 qlge_get_ethtool_stats(struct net_device *ndev,
0365 struct ethtool_stats *stats, u64 *data)
0366 {
0367 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0368 int index, length;
0369
0370 length = QLGE_STATS_LEN;
0371 qlge_update_stats(qdev);
0372
0373 for (index = 0; index < length; index++) {
0374 char *p = (char *)qdev +
0375 qlge_gstrings_stats[index].stat_offset;
0376 *data++ = (qlge_gstrings_stats[index].sizeof_stat ==
0377 sizeof(u64)) ? *(u64 *)p : (*(u32 *)p);
0378 }
0379 }
0380
0381 static int qlge_get_link_ksettings(struct net_device *ndev,
0382 struct ethtool_link_ksettings *ecmd)
0383 {
0384 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0385 u32 supported, advertising;
0386
0387 supported = SUPPORTED_10000baseT_Full;
0388 advertising = ADVERTISED_10000baseT_Full;
0389
0390 if ((qdev->link_status & STS_LINK_TYPE_MASK) ==
0391 STS_LINK_TYPE_10GBASET) {
0392 supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
0393 advertising |= (ADVERTISED_TP | ADVERTISED_Autoneg);
0394 ecmd->base.port = PORT_TP;
0395 ecmd->base.autoneg = AUTONEG_ENABLE;
0396 } else {
0397 supported |= SUPPORTED_FIBRE;
0398 advertising |= ADVERTISED_FIBRE;
0399 ecmd->base.port = PORT_FIBRE;
0400 }
0401
0402 ecmd->base.speed = SPEED_10000;
0403 ecmd->base.duplex = DUPLEX_FULL;
0404
0405 ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.supported,
0406 supported);
0407 ethtool_convert_legacy_u32_to_link_mode(ecmd->link_modes.advertising,
0408 advertising);
0409
0410 return 0;
0411 }
0412
0413 static void qlge_get_drvinfo(struct net_device *ndev,
0414 struct ethtool_drvinfo *drvinfo)
0415 {
0416 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0417
0418 strscpy(drvinfo->driver, qlge_driver_name, sizeof(drvinfo->driver));
0419 strscpy(drvinfo->version, qlge_driver_version,
0420 sizeof(drvinfo->version));
0421 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
0422 "v%d.%d.%d",
0423 (qdev->fw_rev_id & 0x00ff0000) >> 16,
0424 (qdev->fw_rev_id & 0x0000ff00) >> 8,
0425 (qdev->fw_rev_id & 0x000000ff));
0426 strscpy(drvinfo->bus_info, pci_name(qdev->pdev),
0427 sizeof(drvinfo->bus_info));
0428 }
0429
0430 static void qlge_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
0431 {
0432 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0433 unsigned short ssys_dev = qdev->pdev->subsystem_device;
0434
0435
0436 if (ssys_dev == QLGE_MEZZ_SSYS_ID_068 ||
0437 ssys_dev == QLGE_MEZZ_SSYS_ID_180) {
0438 wol->supported = WAKE_MAGIC;
0439 wol->wolopts = qdev->wol;
0440 }
0441 }
0442
0443 static int qlge_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
0444 {
0445 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0446 unsigned short ssys_dev = qdev->pdev->subsystem_device;
0447
0448
0449 if (ssys_dev != QLGE_MEZZ_SSYS_ID_068 &&
0450 ssys_dev != QLGE_MEZZ_SSYS_ID_180) {
0451 netif_info(qdev, drv, qdev->ndev,
0452 "WOL is only supported for mezz card\n");
0453 return -EOPNOTSUPP;
0454 }
0455 if (wol->wolopts & ~WAKE_MAGIC)
0456 return -EINVAL;
0457 qdev->wol = wol->wolopts;
0458
0459 netif_info(qdev, drv, qdev->ndev, "Set wol option 0x%x\n", qdev->wol);
0460 return 0;
0461 }
0462
0463 static int qlge_set_phys_id(struct net_device *ndev,
0464 enum ethtool_phys_id_state state)
0465
0466 {
0467 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0468
0469 switch (state) {
0470 case ETHTOOL_ID_ACTIVE:
0471
0472 if (qlge_mb_get_led_cfg(qdev))
0473 return -EIO;
0474
0475
0476 qlge_mb_set_led_cfg(qdev, QL_LED_BLINK);
0477 return 0;
0478
0479 case ETHTOOL_ID_INACTIVE:
0480
0481 if (qlge_mb_set_led_cfg(qdev, qdev->led_config))
0482 return -EIO;
0483 return 0;
0484
0485 default:
0486 return -EINVAL;
0487 }
0488 }
0489
0490 static int qlge_start_loopback(struct qlge_adapter *qdev)
0491 {
0492 if (netif_carrier_ok(qdev->ndev)) {
0493 set_bit(QL_LB_LINK_UP, &qdev->flags);
0494 netif_carrier_off(qdev->ndev);
0495 } else {
0496 clear_bit(QL_LB_LINK_UP, &qdev->flags);
0497 }
0498 qdev->link_config |= CFG_LOOPBACK_PCS;
0499 return qlge_mb_set_port_cfg(qdev);
0500 }
0501
0502 static void qlge_stop_loopback(struct qlge_adapter *qdev)
0503 {
0504 qdev->link_config &= ~CFG_LOOPBACK_PCS;
0505 qlge_mb_set_port_cfg(qdev);
0506 if (test_bit(QL_LB_LINK_UP, &qdev->flags)) {
0507 netif_carrier_on(qdev->ndev);
0508 clear_bit(QL_LB_LINK_UP, &qdev->flags);
0509 }
0510 }
0511
0512 static void qlge_create_lb_frame(struct sk_buff *skb,
0513 unsigned int frame_size)
0514 {
0515 memset(skb->data, 0xFF, frame_size);
0516 frame_size &= ~1;
0517 memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
0518 skb->data[frame_size / 2 + 10] = (unsigned char)0xBE;
0519 skb->data[frame_size / 2 + 12] = (unsigned char)0xAF;
0520 }
0521
0522 void qlge_check_lb_frame(struct qlge_adapter *qdev,
0523 struct sk_buff *skb)
0524 {
0525 unsigned int frame_size = skb->len;
0526
0527 if ((*(skb->data + 3) == 0xFF) &&
0528 (*(skb->data + frame_size / 2 + 10) == 0xBE) &&
0529 (*(skb->data + frame_size / 2 + 12) == 0xAF)) {
0530 atomic_dec(&qdev->lb_count);
0531 return;
0532 }
0533 }
0534
0535 static int qlge_run_loopback_test(struct qlge_adapter *qdev)
0536 {
0537 int i;
0538 netdev_tx_t rc;
0539 struct sk_buff *skb;
0540 unsigned int size = SMALL_BUF_MAP_SIZE;
0541
0542 for (i = 0; i < 64; i++) {
0543 skb = netdev_alloc_skb(qdev->ndev, size);
0544 if (!skb)
0545 return -ENOMEM;
0546
0547 skb->queue_mapping = 0;
0548 skb_put(skb, size);
0549 qlge_create_lb_frame(skb, size);
0550 rc = qlge_lb_send(skb, qdev->ndev);
0551 if (rc != NETDEV_TX_OK)
0552 return -EPIPE;
0553 atomic_inc(&qdev->lb_count);
0554 }
0555
0556 usleep_range(2000, 2100);
0557 qlge_clean_lb_rx_ring(&qdev->rx_ring[0], 128);
0558 return atomic_read(&qdev->lb_count) ? -EIO : 0;
0559 }
0560
0561 static int qlge_loopback_test(struct qlge_adapter *qdev, u64 *data)
0562 {
0563 *data = qlge_start_loopback(qdev);
0564 if (*data)
0565 goto out;
0566 *data = qlge_run_loopback_test(qdev);
0567 out:
0568 qlge_stop_loopback(qdev);
0569 return *data;
0570 }
0571
0572 static void qlge_self_test(struct net_device *ndev,
0573 struct ethtool_test *eth_test, u64 *data)
0574 {
0575 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0576
0577 memset(data, 0, sizeof(u64) * QLGE_TEST_LEN);
0578
0579 if (netif_running(ndev)) {
0580 set_bit(QL_SELFTEST, &qdev->flags);
0581 if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
0582
0583 if (qlge_loopback_test(qdev, &data[0]))
0584 eth_test->flags |= ETH_TEST_FL_FAILED;
0585
0586 } else {
0587
0588 data[0] = 0;
0589 }
0590 clear_bit(QL_SELFTEST, &qdev->flags);
0591
0592
0593
0594 msleep_interruptible(4 * 1000);
0595 } else {
0596 netif_err(qdev, drv, qdev->ndev,
0597 "is down, Loopback test will fail.\n");
0598 eth_test->flags |= ETH_TEST_FL_FAILED;
0599 }
0600 }
0601
0602 static int qlge_get_regs_len(struct net_device *ndev)
0603 {
0604 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0605
0606 if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
0607 return sizeof(struct qlge_mpi_coredump);
0608 else
0609 return sizeof(struct qlge_reg_dump);
0610 }
0611
0612 static void qlge_get_regs(struct net_device *ndev,
0613 struct ethtool_regs *regs, void *p)
0614 {
0615 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0616
0617 qlge_get_dump(qdev, p);
0618 if (!test_bit(QL_FRC_COREDUMP, &qdev->flags))
0619 regs->len = sizeof(struct qlge_mpi_coredump);
0620 else
0621 regs->len = sizeof(struct qlge_reg_dump);
0622 }
0623
0624 static int qlge_get_coalesce(struct net_device *ndev,
0625 struct ethtool_coalesce *c,
0626 struct kernel_ethtool_coalesce *kernel_coal,
0627 struct netlink_ext_ack *extack)
0628 {
0629 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0630
0631 c->rx_coalesce_usecs = qdev->rx_coalesce_usecs;
0632 c->tx_coalesce_usecs = qdev->tx_coalesce_usecs;
0633
0634
0635
0636
0637
0638
0639
0640
0641
0642
0643
0644 c->rx_max_coalesced_frames = qdev->rx_max_coalesced_frames;
0645 c->tx_max_coalesced_frames = qdev->tx_max_coalesced_frames;
0646
0647 return 0;
0648 }
0649
0650 static int qlge_set_coalesce(struct net_device *ndev,
0651 struct ethtool_coalesce *c,
0652 struct kernel_ethtool_coalesce *kernel_coal,
0653 struct netlink_ext_ack *extack)
0654 {
0655 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0656
0657
0658 if (c->rx_coalesce_usecs > qdev->rx_ring_size / 2)
0659 return -EINVAL;
0660
0661 if (c->rx_max_coalesced_frames > MAX_INTER_FRAME_WAIT)
0662 return -EINVAL;
0663 if (c->tx_coalesce_usecs > qdev->tx_ring_size / 2)
0664 return -EINVAL;
0665 if (c->tx_max_coalesced_frames > MAX_INTER_FRAME_WAIT)
0666 return -EINVAL;
0667
0668
0669 if (qdev->rx_coalesce_usecs == c->rx_coalesce_usecs &&
0670 qdev->tx_coalesce_usecs == c->tx_coalesce_usecs &&
0671 qdev->rx_max_coalesced_frames == c->rx_max_coalesced_frames &&
0672 qdev->tx_max_coalesced_frames == c->tx_max_coalesced_frames)
0673 return 0;
0674
0675 qdev->rx_coalesce_usecs = c->rx_coalesce_usecs;
0676 qdev->tx_coalesce_usecs = c->tx_coalesce_usecs;
0677 qdev->rx_max_coalesced_frames = c->rx_max_coalesced_frames;
0678 qdev->tx_max_coalesced_frames = c->tx_max_coalesced_frames;
0679
0680 return qlge_update_ring_coalescing(qdev);
0681 }
0682
0683 static void qlge_get_pauseparam(struct net_device *ndev,
0684 struct ethtool_pauseparam *pause)
0685 {
0686 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0687
0688 qlge_mb_get_port_cfg(qdev);
0689 if (qdev->link_config & CFG_PAUSE_STD) {
0690 pause->rx_pause = 1;
0691 pause->tx_pause = 1;
0692 }
0693 }
0694
0695 static int qlge_set_pauseparam(struct net_device *ndev,
0696 struct ethtool_pauseparam *pause)
0697 {
0698 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0699
0700 if ((pause->rx_pause) && (pause->tx_pause))
0701 qdev->link_config |= CFG_PAUSE_STD;
0702 else if (!pause->rx_pause && !pause->tx_pause)
0703 qdev->link_config &= ~CFG_PAUSE_STD;
0704 else
0705 return -EINVAL;
0706
0707 return qlge_mb_set_port_cfg(qdev);
0708 }
0709
0710 static u32 qlge_get_msglevel(struct net_device *ndev)
0711 {
0712 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0713
0714 return qdev->msg_enable;
0715 }
0716
0717 static void qlge_set_msglevel(struct net_device *ndev, u32 value)
0718 {
0719 struct qlge_adapter *qdev = netdev_to_qdev(ndev);
0720
0721 qdev->msg_enable = value;
0722 }
0723
0724 const struct ethtool_ops qlge_ethtool_ops = {
0725 .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
0726 ETHTOOL_COALESCE_MAX_FRAMES,
0727 .get_drvinfo = qlge_get_drvinfo,
0728 .get_wol = qlge_get_wol,
0729 .set_wol = qlge_set_wol,
0730 .get_regs_len = qlge_get_regs_len,
0731 .get_regs = qlge_get_regs,
0732 .get_msglevel = qlge_get_msglevel,
0733 .set_msglevel = qlge_set_msglevel,
0734 .get_link = ethtool_op_get_link,
0735 .set_phys_id = qlge_set_phys_id,
0736 .self_test = qlge_self_test,
0737 .get_pauseparam = qlge_get_pauseparam,
0738 .set_pauseparam = qlge_set_pauseparam,
0739 .get_coalesce = qlge_get_coalesce,
0740 .set_coalesce = qlge_set_coalesce,
0741 .get_sset_count = qlge_get_sset_count,
0742 .get_strings = qlge_get_strings,
0743 .get_ethtool_stats = qlge_get_ethtool_stats,
0744 .get_link_ksettings = qlge_get_link_ksettings,
0745 };
0746