Commit 3faac215 authored by Masakazu Mokuno's avatar Masakazu Mokuno Committed by Paul Mackerras

[POWERPC] PS3: Gelic network driver Wake-on-LAN support

Add Wake-on-LAN support to the PS3 Gelic network driver.
Other OS WOL support was introduced in PS3 system firmware 2.20.
Signed-off-by: default avatarMasakazu Mokuno <mokuno@sm.sony.co.jp>
Signed-off-by: default avatarGeoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent 1c43d265
......@@ -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,
};
/**
......
......@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment