ps3: gelic: updown_lock semaphore to mutex
[safe/jmp/linux-2.6] / drivers / net / ps3_gelic_net.c
index c9dd9c0..2eb54fd 100644 (file)
 #include <asm/lv1call.h>
 
 #include "ps3_gelic_net.h"
+#include "ps3_gelic_wireless.h"
 
 #define DRV_NAME "Gelic Network Driver"
-#define DRV_VERSION "1.1"
+#define DRV_VERSION "2.0"
 
 MODULE_AUTHOR("SCE Inc.");
 MODULE_DESCRIPTION("Gelic Network driver");
@@ -109,7 +110,7 @@ static void gelic_card_get_ether_port_status(struct gelic_card *card,
 void gelic_card_up(struct gelic_card *card)
 {
        pr_debug("%s: called\n", __func__);
-       down(&card->updown_lock);
+       mutex_lock(&card->updown_lock);
        if (atomic_inc_return(&card->users) == 1) {
                pr_debug("%s: real do\n", __func__);
                /* enable irq */
@@ -119,7 +120,7 @@ void gelic_card_up(struct gelic_card *card)
 
                napi_enable(&card->napi);
        }
-       up(&card->updown_lock);
+       mutex_unlock(&card->updown_lock);
        pr_debug("%s: done\n", __func__);
 }
 
@@ -127,7 +128,7 @@ void gelic_card_down(struct gelic_card *card)
 {
        u64 mask;
        pr_debug("%s: called\n", __func__);
-       down(&card->updown_lock);
+       mutex_lock(&card->updown_lock);
        if (atomic_dec_if_positive(&card->users) == 0) {
                pr_debug("%s: real do\n", __func__);
                napi_disable(&card->napi);
@@ -145,7 +146,7 @@ void gelic_card_down(struct gelic_card *card)
                /* stop tx */
                gelic_card_disable_txdmac(card);
        }
-       up(&card->updown_lock);
+       mutex_unlock(&card->updown_lock);
        pr_debug("%s: done\n", __func__);
 }
 
@@ -1154,6 +1155,12 @@ static irqreturn_t gelic_card_interrupt(int irq, void *ptr)
        if (status & GELIC_CARD_PORT_STATUS_CHANGED)
                gelic_card_get_ether_port_status(card, 1);
 
+#ifdef CONFIG_GELIC_WIRELESS
+       if (status & (GELIC_CARD_WLAN_EVENT_RECEIVED |
+                     GELIC_CARD_WLAN_COMMAND_COMPLETED))
+               gelic_wl_interrupt(card->netdev[GELIC_PORT_WIRELESS], status);
+#endif
+
        return IRQ_HANDLED;
 }
 
@@ -1259,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,
@@ -1267,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,
 };
 
 /**
@@ -1446,7 +1534,7 @@ static struct gelic_card *gelic_alloc_card_net(struct net_device **netdev)
        INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task);
        init_waitqueue_head(&card->waitq);
        atomic_set(&card->tx_timeout_task_counter, 0);
-       init_MUTEX(&card->updown_lock);
+       mutex_init(&card->updown_lock);
        atomic_set(&card->users, 0);
 
        return card;
@@ -1635,6 +1723,12 @@ static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev)
                goto fail_setup_netdev;
        }
 
+#ifdef CONFIG_GELIC_WIRELESS
+       if (gelic_wl_driver_probe(card)) {
+               dev_dbg(&dev->core, "%s: WL init failed\n", __func__);
+               goto fail_setup_netdev;
+       }
+#endif
        pr_debug("%s: done\n", __func__);
        return 0;
 
@@ -1674,6 +1768,9 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev)
        struct net_device *netdev0;
        pr_debug("%s: called\n", __func__);
 
+#ifdef CONFIG_GELIC_WIRELESS
+       gelic_wl_driver_remove(card);
+#endif
        /* stop interrupt */
        gelic_card_set_irq_mask(card, 0);