diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ps3_gelic_net.c | 81 | ||||
-rw-r--r-- | drivers/net/ps3_gelic_net.h | 20 |
2 files changed, 101 insertions, 0 deletions
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 7eb6e7e848f..e365efb3c62 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, }; /** diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index 1d39d06797e..520f143c2c0 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -182,12 +182,32 @@ enum gelic_lv1_net_control_code { GELIC_LV1_GET_ETH_PORT_STATUS = 2, GELIC_LV1_SET_NEGOTIATION_MODE = 3, GELIC_LV1_GET_VLAN_ID = 4, + GELIC_LV1_SET_WOL = 5, GELIC_LV1_GET_CHANNEL = 6, GELIC_LV1_POST_WLAN_CMD = 9, GELIC_LV1_GET_WLAN_CMD_RESULT = 10, GELIC_LV1_GET_WLAN_EVENT = 11 }; +/* for GELIC_LV1_SET_WOL */ +enum gelic_lv1_wol_command { + GELIC_LV1_WOL_MAGIC_PACKET = 1, + GELIC_LV1_WOL_ADD_MATCH_ADDR = 6, + GELIC_LV1_WOL_DELETE_MATCH_ADDR = 7, +}; + +/* for GELIC_LV1_WOL_MAGIC_PACKET */ +enum gelic_lv1_wol_mp_arg { + GELIC_LV1_WOL_MP_DISABLE = 0, + GELIC_LV1_WOL_MP_ENABLE = 1, +}; + +/* for GELIC_LV1_WOL_{ADD,DELETE}_MATCH_ADDR */ +enum gelic_lv1_wol_match_arg { + GELIC_LV1_WOL_MATCH_INDIVIDUAL = 0, + GELIC_LV1_WOL_MATCH_ALL = 1, +}; + /* status returened from GET_ETH_PORT_STATUS */ enum gelic_lv1_ether_port_status { GELIC_LV1_ETHER_LINK_UP = 0x0000000000000001L, |