diff options
Diffstat (limited to 'drivers/net/ps3_gelic_net.c')
-rw-r--r-- | drivers/net/ps3_gelic_net.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 7eb6e7e848f4..e365efb3c627 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1266,6 +1266,85 @@ int gelic_net_set_rx_csum(struct net_device *netdev, u32 data) return 0; } +static void gelic_net_get_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + if (0 <= ps3_compare_firmware_version(2, 2, 0)) + wol->supported = WAKE_MAGIC; + else + wol->supported = 0; + + wol->wolopts = ps3_sys_manager_get_wol() ? wol->supported : 0; + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} +static int gelic_net_set_wol(struct net_device *netdev, + struct ethtool_wolinfo *wol) +{ + int status; + struct gelic_card *card; + u64 v1, v2; + + if (ps3_compare_firmware_version(2, 2, 0) < 0 || + !capable(CAP_NET_ADMIN)) + return -EPERM; + + if (wol->wolopts & ~WAKE_MAGIC) + return -EINVAL; + + card = netdev_card(netdev); + if (wol->wolopts & WAKE_MAGIC) { + status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_SET_WOL, + GELIC_LV1_WOL_MAGIC_PACKET, + 0, GELIC_LV1_WOL_MP_ENABLE, + &v1, &v2); + if (status) { + pr_info("%s: enabling WOL failed %d\n", __func__, + status); + status = -EIO; + goto done; + } + status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_SET_WOL, + GELIC_LV1_WOL_ADD_MATCH_ADDR, + 0, GELIC_LV1_WOL_MATCH_ALL, + &v1, &v2); + if (!status) + ps3_sys_manager_set_wol(1); + else { + pr_info("%s: enabling WOL filter failed %d\n", + __func__, status); + status = -EIO; + } + } else { + status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_SET_WOL, + GELIC_LV1_WOL_MAGIC_PACKET, + 0, GELIC_LV1_WOL_MP_DISABLE, + &v1, &v2); + if (status) { + pr_info("%s: disabling WOL failed %d\n", __func__, + status); + status = -EIO; + goto done; + } + status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_SET_WOL, + GELIC_LV1_WOL_DELETE_MATCH_ADDR, + 0, GELIC_LV1_WOL_MATCH_ALL, + &v1, &v2); + if (!status) + ps3_sys_manager_set_wol(0); + else { + pr_info("%s: removing WOL filter failed %d\n", + __func__, status); + status = -EIO; + } + } +done: + return status; +} + static struct ethtool_ops gelic_ether_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, .get_settings = gelic_ether_get_settings, @@ -1274,6 +1353,8 @@ static struct ethtool_ops gelic_ether_ethtool_ops = { .set_tx_csum = ethtool_op_set_tx_csum, .get_rx_csum = gelic_net_get_rx_csum, .set_rx_csum = gelic_net_set_rx_csum, + .get_wol = gelic_net_get_wol, + .set_wol = gelic_net_set_wol, }; /** |