Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-atlantic-phy-tunables-from-mac-driver'

Igor Russkikh says:

====================
net: atlantic: phy tunables from mac driver

This series implements phy tunables settings via MAC driver callbacks.

AQC 10G devices use integrated MAC+PHY solution, where PHY is fully controlled
by MAC firmware. Therefore, it is not possible to implement separate phy driver
for these.

We use ethtool ops callbacks to implement downshift and EDPC tunables.

v3: fixed flaw in EDPD logic, from Andrew
v2: comments from Andrew
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+191 -13
+53
drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c
··· 917 917 return ret; 918 918 } 919 919 920 + static int aq_ethtool_get_phy_tunable(struct net_device *ndev, 921 + const struct ethtool_tunable *tuna, void *data) 922 + { 923 + struct aq_nic_s *aq_nic = netdev_priv(ndev); 924 + 925 + switch (tuna->id) { 926 + case ETHTOOL_PHY_EDPD: { 927 + u16 *val = data; 928 + 929 + *val = aq_nic->aq_nic_cfg.is_media_detect ? AQ_HW_MEDIA_DETECT_CNT : 0; 930 + break; 931 + } 932 + case ETHTOOL_PHY_DOWNSHIFT: { 933 + u8 *val = data; 934 + 935 + *val = (u8)aq_nic->aq_nic_cfg.downshift_counter; 936 + break; 937 + } 938 + default: 939 + return -EOPNOTSUPP; 940 + } 941 + 942 + return 0; 943 + } 944 + 945 + static int aq_ethtool_set_phy_tunable(struct net_device *ndev, 946 + const struct ethtool_tunable *tuna, const void *data) 947 + { 948 + int err = -EOPNOTSUPP; 949 + struct aq_nic_s *aq_nic = netdev_priv(ndev); 950 + 951 + switch (tuna->id) { 952 + case ETHTOOL_PHY_EDPD: { 953 + const u16 *val = data; 954 + 955 + err = aq_nic_set_media_detect(aq_nic, *val); 956 + break; 957 + } 958 + case ETHTOOL_PHY_DOWNSHIFT: { 959 + const u8 *val = data; 960 + 961 + err = aq_nic_set_downshift(aq_nic, *val); 962 + break; 963 + } 964 + default: 965 + break; 966 + } 967 + 968 + return err; 969 + } 970 + 920 971 const struct ethtool_ops aq_ethtool_ops = { 921 972 .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 922 973 ETHTOOL_COALESCE_MAX_FRAMES, ··· 1003 952 .get_coalesce = aq_ethtool_get_coalesce, 1004 953 .set_coalesce = aq_ethtool_set_coalesce, 1005 954 .get_ts_info = aq_ethtool_get_ts_info, 955 + .get_phy_tunable = aq_ethtool_get_phy_tunable, 956 + .set_phy_tunable = aq_ethtool_set_phy_tunable, 1006 957 };
+6
drivers/net/ethernet/aquantia/atlantic/aq_hw.h
··· 143 143 #define AQ_HW_LED_BLINK 0x2U 144 144 #define AQ_HW_LED_DEFAULT 0x0U 145 145 146 + #define AQ_HW_MEDIA_DETECT_CNT 6000 147 + 146 148 enum aq_priv_flags { 147 149 AQ_HW_LOOPBACK_DMA_SYS, 148 150 AQ_HW_LOOPBACK_PKT_SYS, ··· 387 385 388 386 int (*get_eee_rate)(struct aq_hw_s *self, u32 *rate, 389 387 u32 *supported_rates); 388 + 389 + int (*set_downshift)(struct aq_hw_s *self, u32 counter); 390 + 391 + int (*set_media_detect)(struct aq_hw_s *self, bool enable); 390 392 391 393 u32 (*get_link_capabilities)(struct aq_hw_s *self); 392 394
+50
drivers/net/ethernet/aquantia/atlantic/aq_nic.c
··· 405 405 mutex_unlock(&self->fwreq_mutex); 406 406 if (err < 0) 407 407 goto err_exit; 408 + /* Restore default settings */ 409 + aq_nic_set_downshift(self, self->aq_nic_cfg.downshift_counter); 410 + aq_nic_set_media_detect(self, self->aq_nic_cfg.is_media_detect ? 411 + AQ_HW_MEDIA_DETECT_CNT : 0); 408 412 409 413 err = self->aq_hw_ops->hw_init(self->aq_hw, 410 414 aq_nic_get_ndev(self)->dev_addr); ··· 1400 1396 default: 1401 1397 break; 1402 1398 } 1399 + } 1400 + 1401 + int aq_nic_set_downshift(struct aq_nic_s *self, int val) 1402 + { 1403 + int err = 0; 1404 + struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 1405 + 1406 + if (!self->aq_fw_ops->set_downshift) 1407 + return -EOPNOTSUPP; 1408 + 1409 + if (val > 15) { 1410 + netdev_err(self->ndev, "downshift counter should be <= 15\n"); 1411 + return -EINVAL; 1412 + } 1413 + cfg->downshift_counter = val; 1414 + 1415 + mutex_lock(&self->fwreq_mutex); 1416 + err = self->aq_fw_ops->set_downshift(self->aq_hw, cfg->downshift_counter); 1417 + mutex_unlock(&self->fwreq_mutex); 1418 + 1419 + return err; 1420 + } 1421 + 1422 + int aq_nic_set_media_detect(struct aq_nic_s *self, int val) 1423 + { 1424 + struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg; 1425 + int err = 0; 1426 + 1427 + if (!self->aq_fw_ops->set_media_detect) 1428 + return -EOPNOTSUPP; 1429 + 1430 + if (val > 0 && val != AQ_HW_MEDIA_DETECT_CNT) { 1431 + netdev_err(self->ndev, "EDPD on this device could have only fixed value of %d\n", 1432 + AQ_HW_MEDIA_DETECT_CNT); 1433 + return -EINVAL; 1434 + } 1435 + 1436 + mutex_lock(&self->fwreq_mutex); 1437 + err = self->aq_fw_ops->set_media_detect(self->aq_hw, !!val); 1438 + mutex_unlock(&self->fwreq_mutex); 1439 + 1440 + /* msecs plays no role - configuration is always fixed in PHY */ 1441 + if (!err) 1442 + cfg->is_media_detect = !!val; 1443 + 1444 + return err; 1403 1445 } 1404 1446 1405 1447 int aq_nic_setup_tc_mqprio(struct aq_nic_s *self, u32 tcs, u8 *prio_tc_map)
+4
drivers/net/ethernet/aquantia/atlantic/aq_nic.h
··· 62 62 bool is_lro; 63 63 bool is_qos; 64 64 bool is_ptp; 65 + bool is_media_detect; 66 + int downshift_counter; 65 67 enum aq_tc_mode tc_mode; 66 68 u32 priv_flags; 67 69 u8 tcs; ··· 197 195 struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self); 198 196 u32 aq_nic_get_fw_version(struct aq_nic_s *self); 199 197 int aq_nic_set_loopback(struct aq_nic_s *self); 198 + int aq_nic_set_downshift(struct aq_nic_s *self, int val); 199 + int aq_nic_set_media_detect(struct aq_nic_s *self, int val); 200 200 int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self); 201 201 void aq_nic_shutdown(struct aq_nic_s *self); 202 202 u8 aq_nic_reserve_filter(struct aq_nic_s *self, enum aq_rx_filter_type type);
+37
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils_fw2x.c
··· 612 612 return aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE2_ADDR); 613 613 } 614 614 615 + static int aq_fw2x_set_downshift(struct aq_hw_s *self, u32 counter) 616 + { 617 + int err = 0; 618 + u32 mpi_opts; 619 + u32 offset; 620 + 621 + offset = offsetof(struct hw_atl_utils_settings, downshift_retry_count); 622 + err = hw_atl_write_fwsettings_dwords(self, offset, &counter, 1); 623 + if (err) 624 + return err; 625 + 626 + mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR); 627 + if (counter) 628 + mpi_opts |= HW_ATL_FW2X_CTRL_DOWNSHIFT; 629 + else 630 + mpi_opts &= ~HW_ATL_FW2X_CTRL_DOWNSHIFT; 631 + aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL2_ADDR, mpi_opts); 632 + 633 + return err; 634 + } 635 + 636 + static int aq_fw2x_set_media_detect(struct aq_hw_s *self, bool on) 637 + { 638 + u32 enable; 639 + u32 offset; 640 + 641 + if (self->fw_ver_actual < HW_ATL_FW_VER_MEDIA_CONTROL) 642 + return -EOPNOTSUPP; 643 + 644 + offset = offsetof(struct hw_atl_utils_settings, media_detect); 645 + enable = on; 646 + 647 + return hw_atl_write_fwsettings_dwords(self, offset, &enable, 1); 648 + } 649 + 615 650 static u32 aq_fw2x_get_link_capabilities(struct aq_hw_s *self) 616 651 { 617 652 int err = 0; ··· 727 692 .enable_ptp = aq_fw3x_enable_ptp, 728 693 .led_control = aq_fw2x_led_control, 729 694 .set_phyloopback = aq_fw2x_set_phyloopback, 695 + .set_downshift = aq_fw2x_set_downshift, 696 + .set_media_detect = aq_fw2x_set_media_detect, 730 697 .adjust_ptp = aq_fw3x_adjust_ptp, 731 698 .get_link_capabilities = aq_fw2x_get_link_capabilities, 732 699 .send_macsec_req = aq_fw2x_send_macsec_req,
+13
drivers/net/ethernet/aquantia/atlantic/hw_atl2/hw_atl2_utils_fw.c
··· 519 519 return 0; 520 520 } 521 521 522 + static int aq_a2_fw_set_downshift(struct aq_hw_s *self, u32 counter) 523 + { 524 + struct link_options_s link_options; 525 + 526 + hw_atl2_shared_buffer_get(self, link_options, link_options); 527 + link_options.downshift = !!counter; 528 + link_options.downshift_retry = counter; 529 + hw_atl2_shared_buffer_write(self, link_options, link_options); 530 + 531 + return hw_atl2_shared_buffer_finish_ack(self); 532 + } 533 + 522 534 const struct aq_fw_ops aq_a2_fw_ops = { 523 535 .init = aq_a2_fw_init, 524 536 .deinit = aq_a2_fw_deinit, ··· 548 536 .set_flow_control = aq_a2_fw_set_flow_control, 549 537 .get_flow_control = aq_a2_fw_get_flow_control, 550 538 .set_phyloopback = aq_a2_fw_set_phyloopback, 539 + .set_downshift = aq_a2_fw_set_downshift, 551 540 };
+4
include/linux/ethtool.h
··· 505 505 struct ethtool_fecparam *); 506 506 void (*get_ethtool_phy_stats)(struct net_device *, 507 507 struct ethtool_stats *, u64 *); 508 + int (*get_phy_tunable)(struct net_device *, 509 + const struct ethtool_tunable *, void *); 510 + int (*set_phy_tunable)(struct net_device *, 511 + const struct ethtool_tunable *, const void *); 508 512 }; 509 513 510 514 int ethtool_check_ops(const struct ethtool_ops *ops);
+24 -13
net/ethtool/ioctl.c
··· 2459 2459 2460 2460 static int get_phy_tunable(struct net_device *dev, void __user *useraddr) 2461 2461 { 2462 - int ret; 2463 - struct ethtool_tunable tuna; 2464 2462 struct phy_device *phydev = dev->phydev; 2463 + struct ethtool_tunable tuna; 2464 + bool phy_drv_tunable; 2465 2465 void *data; 2466 + int ret; 2466 2467 2467 - if (!(phydev && phydev->drv && phydev->drv->get_tunable)) 2468 + phy_drv_tunable = phydev && phydev->drv && phydev->drv->get_tunable; 2469 + if (!phy_drv_tunable && !dev->ethtool_ops->get_phy_tunable) 2468 2470 return -EOPNOTSUPP; 2469 - 2470 2471 if (copy_from_user(&tuna, useraddr, sizeof(tuna))) 2471 2472 return -EFAULT; 2472 2473 ret = ethtool_phy_tunable_valid(&tuna); ··· 2476 2475 data = kmalloc(tuna.len, GFP_USER); 2477 2476 if (!data) 2478 2477 return -ENOMEM; 2479 - mutex_lock(&phydev->lock); 2480 - ret = phydev->drv->get_tunable(phydev, &tuna, data); 2481 - mutex_unlock(&phydev->lock); 2478 + if (phy_drv_tunable) { 2479 + mutex_lock(&phydev->lock); 2480 + ret = phydev->drv->get_tunable(phydev, &tuna, data); 2481 + mutex_unlock(&phydev->lock); 2482 + } else { 2483 + ret = dev->ethtool_ops->get_phy_tunable(dev, &tuna, data); 2484 + } 2482 2485 if (ret) 2483 2486 goto out; 2484 2487 useraddr += sizeof(tuna); ··· 2498 2493 2499 2494 static int set_phy_tunable(struct net_device *dev, void __user *useraddr) 2500 2495 { 2501 - int ret; 2502 - struct ethtool_tunable tuna; 2503 2496 struct phy_device *phydev = dev->phydev; 2497 + struct ethtool_tunable tuna; 2498 + bool phy_drv_tunable; 2504 2499 void *data; 2500 + int ret; 2505 2501 2506 - if (!(phydev && phydev->drv && phydev->drv->set_tunable)) 2502 + phy_drv_tunable = phydev && phydev->drv && phydev->drv->get_tunable; 2503 + if (!phy_drv_tunable && !dev->ethtool_ops->set_phy_tunable) 2507 2504 return -EOPNOTSUPP; 2508 2505 if (copy_from_user(&tuna, useraddr, sizeof(tuna))) 2509 2506 return -EFAULT; ··· 2516 2509 data = memdup_user(useraddr, tuna.len); 2517 2510 if (IS_ERR(data)) 2518 2511 return PTR_ERR(data); 2519 - mutex_lock(&phydev->lock); 2520 - ret = phydev->drv->set_tunable(phydev, &tuna, data); 2521 - mutex_unlock(&phydev->lock); 2512 + if (phy_drv_tunable) { 2513 + mutex_lock(&phydev->lock); 2514 + ret = phydev->drv->set_tunable(phydev, &tuna, data); 2515 + mutex_unlock(&phydev->lock); 2516 + } else { 2517 + ret = dev->ethtool_ops->set_phy_tunable(dev, &tuna, data); 2518 + } 2522 2519 2523 2520 kfree(data); 2524 2521 return ret;