diff options
Diffstat (limited to 'drivers/net/ps3_gelic_net.c')
-rw-r--r-- | drivers/net/ps3_gelic_net.c | 98 |
1 files changed, 83 insertions, 15 deletions
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index b211613e9dbd..89c4948300a5 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -95,11 +95,11 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card, lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_GET_ETH_PORT_STATUS, - GELIC_LV1_VLAN_TX_ETHERNET, 0, 0, + GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0, &card->ether_port_status, &v2); if (inform) { - ether_netdev = card->netdev[GELIC_PORT_ETHERNET]; + ether_netdev = card->netdev[GELIC_PORT_ETHERNET_0]; if (card->ether_port_status & GELIC_LV1_ETHER_LINK_UP) netif_carrier_on(ether_netdev); else @@ -107,6 +107,24 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card, } } +static int gelic_card_set_link_mode(struct gelic_card *card, int mode) +{ + int status; + u64 v1, v2; + + status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_SET_NEGOTIATION_MODE, + GELIC_LV1_PHY_ETHERNET_0, mode, 0, &v1, &v2); + if (status) { + pr_info("%s: failed setting negotiation mode %d\n", __func__, + status); + return -EBUSY; + } + + card->link_mode = mode; + return 0; +} + void gelic_card_up(struct gelic_card *card) { pr_debug("%s: called\n", __func__); @@ -451,14 +469,14 @@ static void gelic_descr_release_tx(struct gelic_card *card, static void gelic_card_stop_queues(struct gelic_card *card) { - netif_stop_queue(card->netdev[GELIC_PORT_ETHERNET]); + netif_stop_queue(card->netdev[GELIC_PORT_ETHERNET_0]); if (card->netdev[GELIC_PORT_WIRELESS]) netif_stop_queue(card->netdev[GELIC_PORT_WIRELESS]); } static void gelic_card_wake_queues(struct gelic_card *card) { - netif_wake_queue(card->netdev[GELIC_PORT_ETHERNET]); + netif_wake_queue(card->netdev[GELIC_PORT_ETHERNET_0]); if (card->netdev[GELIC_PORT_WIRELESS]) netif_wake_queue(card->netdev[GELIC_PORT_WIRELESS]); @@ -999,7 +1017,7 @@ static int gelic_card_decode_one_descr(struct gelic_card *card) goto refill; } } else - netdev = card->netdev[GELIC_PORT_ETHERNET]; + netdev = card->netdev[GELIC_PORT_ETHERNET_0]; if ((status == GELIC_DESCR_DMA_RESPONSE_ERROR) || (status == GELIC_DESCR_DMA_PROTECTION_ERROR) || @@ -1244,14 +1262,58 @@ static int gelic_ether_get_settings(struct net_device *netdev, cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; + SUPPORTED_1000baseT_Full; cmd->advertising = cmd->supported; - cmd->autoneg = AUTONEG_ENABLE; /* always enabled */ + if (card->link_mode & GELIC_LV1_ETHER_AUTO_NEG) { + cmd->autoneg = AUTONEG_ENABLE; + } else { + cmd->autoneg = AUTONEG_DISABLE; + cmd->advertising &= ~ADVERTISED_Autoneg; + } cmd->port = PORT_TP; return 0; } +static int gelic_ether_set_settings(struct net_device *netdev, + struct ethtool_cmd *cmd) +{ + struct gelic_card *card = netdev_card(netdev); + u64 mode; + int ret; + + if (cmd->autoneg == AUTONEG_ENABLE) { + mode = GELIC_LV1_ETHER_AUTO_NEG; + } else { + switch (cmd->speed) { + case SPEED_10: + mode = GELIC_LV1_ETHER_SPEED_10; + break; + case SPEED_100: + mode = GELIC_LV1_ETHER_SPEED_100; + break; + case SPEED_1000: + mode = GELIC_LV1_ETHER_SPEED_1000; + break; + default: + return -EINVAL; + } + if (cmd->duplex == DUPLEX_FULL) + mode |= GELIC_LV1_ETHER_FULL_DUPLEX; + else if (cmd->speed == SPEED_1000) { + pr_info("1000 half duplex is not supported.\n"); + return -EINVAL; + } + } + + ret = gelic_card_set_link_mode(card, mode); + + if (ret) + return ret; + + return 0; +} + u32 gelic_net_get_rx_csum(struct net_device *netdev) { struct gelic_card *card = netdev_card(netdev); @@ -1349,6 +1411,7 @@ done: static const struct ethtool_ops gelic_ether_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, .get_settings = gelic_ether_get_settings, + .set_settings = gelic_ether_set_settings, .get_link = ethtool_op_get_link, .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = ethtool_op_set_tx_csum, @@ -1369,7 +1432,7 @@ static void gelic_net_tx_timeout_task(struct work_struct *work) { struct gelic_card *card = container_of(work, struct gelic_card, tx_timeout_task); - struct net_device *netdev = card->netdev[GELIC_PORT_ETHERNET]; + struct net_device *netdev = card->netdev[GELIC_PORT_ETHERNET_0]; dev_info(ctodev(card), "%s:Timed out. Restarting... \n", __func__); @@ -1531,10 +1594,10 @@ static struct gelic_card * __devinit gelic_alloc_card_net(struct net_device **ne /* gelic_port */ port->netdev = *netdev; port->card = card; - port->type = GELIC_PORT_ETHERNET; + port->type = GELIC_PORT_ETHERNET_0; /* gelic_card */ - card->netdev[GELIC_PORT_ETHERNET] = *netdev; + card->netdev[GELIC_PORT_ETHERNET_0] = *netdev; INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task); init_waitqueue_head(&card->waitq); @@ -1554,9 +1617,9 @@ static void __devinit gelic_card_get_vlan_info(struct gelic_card *card) int tx; int rx; } vlan_id_ix[2] = { - [GELIC_PORT_ETHERNET] = { - .tx = GELIC_LV1_VLAN_TX_ETHERNET, - .rx = GELIC_LV1_VLAN_RX_ETHERNET + [GELIC_PORT_ETHERNET_0] = { + .tx = GELIC_LV1_VLAN_TX_ETHERNET_0, + .rx = GELIC_LV1_VLAN_RX_ETHERNET_0 }, [GELIC_PORT_WIRELESS] = { .tx = GELIC_LV1_VLAN_TX_WIRELESS, @@ -1601,7 +1664,7 @@ static void __devinit gelic_card_get_vlan_info(struct gelic_card *card) i, card->vlan[i].tx, card->vlan[i].rx); } - if (card->vlan[GELIC_PORT_ETHERNET].tx) { + if (card->vlan[GELIC_PORT_ETHERNET_0].tx) { BUG_ON(!card->vlan[GELIC_PORT_WIRELESS].tx); card->vlan_required = 1; } else @@ -1657,6 +1720,8 @@ static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) /* get internal vlan info */ gelic_card_get_vlan_info(card); + card->link_mode = GELIC_LV1_ETHER_AUTO_NEG; + /* setup interrupt */ result = lv1_net_set_interrupt_status_indicator(bus_id(card), dev_id(card), @@ -1773,6 +1838,9 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) struct net_device *netdev0; pr_debug("%s: called\n", __func__); + /* set auto-negotiation */ + gelic_card_set_link_mode(card, GELIC_LV1_ETHER_AUTO_NEG); + #ifdef CONFIG_GELIC_WIRELESS gelic_wl_driver_remove(card); #endif @@ -1790,7 +1858,7 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) gelic_card_free_chain(card, card->tx_top); gelic_card_free_chain(card, card->rx_top); - netdev0 = card->netdev[GELIC_PORT_ETHERNET]; + netdev0 = card->netdev[GELIC_PORT_ETHERNET_0]; /* disconnect event port */ free_irq(card->irq, card); netdev0->irq = NO_IRQ; |