]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/brcm80211/brcmfmac/usb.c
brcmfmac: remove firmware list from USB driver
[karo-tx-linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / usb.c
index 24f65cd538595a84e6c66b62b8698bbc97456288..6db51a666f619abedaee11ac4822b917b24b4f3c 100644 (file)
@@ -25,6 +25,7 @@
 #include <dhd_bus.h>
 #include <dhd_dbg.h>
 
+#include "firmware.h"
 #include "usb_rdl.h"
 #include "usb.h"
 
@@ -61,12 +62,6 @@ struct brcmf_usb_image {
        u8 *image;
        int image_len;
 };
-static struct list_head fw_image_list;
-
-struct intr_transfer_buf {
-       u32 notification;
-       u32 reserved;
-};
 
 struct brcmf_usbdev_info {
        struct brcmf_usbdev bus_pub; /* MUST BE FIRST */
@@ -75,7 +70,7 @@ struct brcmf_usbdev_info {
        struct list_head rx_postq;
        struct list_head tx_freeq;
        struct list_head tx_postq;
-       uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2;
+       uint rx_pipe, tx_pipe, rx_pipe2;
 
        int rx_low_watermark;
        int tx_low_watermark;
@@ -87,7 +82,7 @@ struct brcmf_usbdev_info {
        struct brcmf_usbreq *tx_reqs;
        struct brcmf_usbreq *rx_reqs;
 
-       u8 *image;      /* buffer for combine fw and nvram */
+       const u8 *image;        /* buffer for combine fw and nvram */
        int image_len;
 
        struct usb_device *usbdev;
@@ -104,10 +99,6 @@ struct brcmf_usbdev_info {
        ulong ctl_op;
 
        struct urb *bulk_urb; /* used for FW download */
-       struct urb *intr_urb; /* URB for interrupt endpoint */
-       int intr_size;          /* Size of interrupt message */
-       int interval;           /* Interrupt polling interval */
-       struct intr_transfer_buf intr; /* Data buffer for interrupt endpoint */
 };
 
 static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
@@ -531,39 +522,6 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
        }
 }
 
-static void
-brcmf_usb_intr_complete(struct urb *urb)
-{
-       struct brcmf_usbdev_info *devinfo =
-                       (struct brcmf_usbdev_info *)urb->context;
-       int err;
-
-       brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
-
-       if (devinfo == NULL)
-               return;
-
-       if (unlikely(urb->status)) {
-               if (urb->status == -ENOENT ||
-                   urb->status == -ESHUTDOWN ||
-                   urb->status == -ENODEV) {
-                       brcmf_usb_state_change(devinfo,
-                                              BRCMFMAC_USB_STATE_DOWN);
-               }
-       }
-
-       if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN) {
-               brcmf_err("intr cb when DBUS down, ignoring\n");
-               return;
-       }
-
-       if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
-               err = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
-               if (err)
-                       brcmf_err("usb_submit_urb, err=%d\n", err);
-       }
-}
-
 static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
 {
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
@@ -619,7 +577,6 @@ static int brcmf_usb_up(struct device *dev)
 {
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
        u16 ifnum;
-       int ret;
 
        brcmf_dbg(USB, "Enter\n");
        if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP)
@@ -628,23 +585,6 @@ static int brcmf_usb_up(struct device *dev)
        /* Success, indicate devinfo is fully up */
        brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_UP);
 
-       if (devinfo->intr_urb) {
-               usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev,
-                       devinfo->intr_pipe,
-                       &devinfo->intr,
-                       devinfo->intr_size,
-                       (usb_complete_t)brcmf_usb_intr_complete,
-                       devinfo,
-                       devinfo->interval);
-
-               ret = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
-               if (ret) {
-                       brcmf_err("USB_SUBMIT_URB failed with status %d\n",
-                                 ret);
-                       return -EINVAL;
-               }
-       }
-
        if (devinfo->ctl_urb) {
                devinfo->ctl_in_pipe = usb_rcvctrlpipe(devinfo->usbdev, 0);
                devinfo->ctl_out_pipe = usb_sndctrlpipe(devinfo->usbdev, 0);
@@ -681,8 +621,6 @@ static void brcmf_usb_down(struct device *dev)
                return;
 
        brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN);
-       if (devinfo->intr_urb)
-               usb_kill_urb(devinfo->intr_urb);
 
        if (devinfo->ctl_urb)
                usb_kill_urb(devinfo->ctl_urb);
@@ -1021,7 +959,7 @@ brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
        }
 
        err = brcmf_usb_dlstart(devinfo,
-               devinfo->image, devinfo->image_len);
+               (u8 *)devinfo->image, devinfo->image_len);
        if (err == 0)
                err = brcmf_usb_dlrun(devinfo);
        return err;
@@ -1036,7 +974,6 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
        brcmf_usb_free_q(&devinfo->rx_freeq, false);
        brcmf_usb_free_q(&devinfo->tx_freeq, false);
 
-       usb_free_urb(devinfo->intr_urb);
        usb_free_urb(devinfo->ctl_urb);
        usb_free_urb(devinfo->bulk_urb);
 
@@ -1080,68 +1017,20 @@ static int check_file(const u8 *headers)
        return -1;
 }
 
-static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
+static const char *brcmf_usb_get_fwname(struct brcmf_usbdev_info *devinfo)
 {
-       s8 *fwname;
-       const struct firmware *fw;
-       struct brcmf_usb_image *fw_image;
-       int err;
-
-       brcmf_dbg(USB, "Enter\n");
        switch (devinfo->bus_pub.devid) {
        case 43143:
-               fwname = BRCMF_USB_43143_FW_NAME;
-               break;
+               return BRCMF_USB_43143_FW_NAME;
        case 43235:
        case 43236:
        case 43238:
-               fwname = BRCMF_USB_43236_FW_NAME;
-               break;
+               return BRCMF_USB_43236_FW_NAME;
        case 43242:
-               fwname = BRCMF_USB_43242_FW_NAME;
-               break;
+               return BRCMF_USB_43242_FW_NAME;
        default:
-               return -EINVAL;
-               break;
-       }
-       brcmf_dbg(USB, "Loading FW %s\n", fwname);
-       list_for_each_entry(fw_image, &fw_image_list, list) {
-               if (fw_image->fwname == fwname) {
-                       devinfo->image = fw_image->image;
-                       devinfo->image_len = fw_image->image_len;
-                       return 0;
-               }
-       }
-       /* fw image not yet loaded. Load it now and add to list */
-       err = request_firmware(&fw, fwname, devinfo->dev);
-       if (!fw) {
-               brcmf_err("fail to request firmware %s\n", fwname);
-               return err;
-       }
-       if (check_file(fw->data) < 0) {
-               brcmf_err("invalid firmware %s\n", fwname);
-               return -EINVAL;
+               return NULL;
        }
-
-       fw_image = kzalloc(sizeof(*fw_image), GFP_ATOMIC);
-       if (!fw_image)
-               return -ENOMEM;
-       INIT_LIST_HEAD(&fw_image->list);
-       list_add_tail(&fw_image->list, &fw_image_list);
-       fw_image->fwname = fwname;
-       fw_image->image = vmalloc(fw->size);
-       if (!fw_image->image)
-               return -ENOMEM;
-
-       memcpy(fw_image->image, fw->data, fw->size);
-       fw_image->image_len = fw->size;
-
-       release_firmware(fw);
-
-       devinfo->image = fw_image->image;
-       devinfo->image_len = fw_image->image_len;
-
-       return 0;
 }
 
 
@@ -1186,11 +1075,6 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
                goto error;
        devinfo->tx_freecount = ntxq;
 
-       devinfo->intr_urb = usb_alloc_urb(0, GFP_ATOMIC);
-       if (!devinfo->intr_urb) {
-               brcmf_err("usb_alloc_urb (intr) failed\n");
-               goto error;
-       }
        devinfo->ctl_urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!devinfo->ctl_urb) {
                brcmf_err("usb_alloc_urb (ctl) failed\n");
@@ -1202,16 +1086,6 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
                goto error;
        }
 
-       if (!brcmf_usb_dlneeded(devinfo))
-               return &devinfo->bus_pub;
-
-       brcmf_dbg(USB, "Start fw downloading\n");
-       if (brcmf_usb_get_fw(devinfo))
-               goto error;
-
-       if (brcmf_usb_fw_download(devinfo))
-               goto error;
-
        return &devinfo->bus_pub;
 
 error:
@@ -1222,18 +1096,77 @@ error:
 
 static struct brcmf_bus_ops brcmf_usb_bus_ops = {
        .txdata = brcmf_usb_tx,
-       .init = brcmf_usb_up,
        .stop = brcmf_usb_down,
        .txctl = brcmf_usb_tx_ctlpkt,
        .rxctl = brcmf_usb_rx_ctlpkt,
 };
 
+static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
+{
+       int ret;
+
+       /* Attach to the common driver interface */
+       ret = brcmf_attach(devinfo->dev);
+       if (ret) {
+               brcmf_err("brcmf_attach failed\n");
+               return ret;
+       }
+
+       ret = brcmf_usb_up(devinfo->dev);
+       if (ret)
+               goto fail;
+
+       ret = brcmf_bus_start(devinfo->dev);
+       if (ret)
+               goto fail;
+
+       return 0;
+fail:
+       brcmf_detach(devinfo->dev);
+       return ret;
+}
+
+static void brcmf_usb_probe_phase2(struct device *dev,
+                                  const struct firmware *fw,
+                                  void *nvram, u32 nvlen)
+{
+       struct brcmf_bus *bus = dev_get_drvdata(dev);
+       struct brcmf_usbdev_info *devinfo;
+       int ret;
+
+       brcmf_dbg(USB, "Start fw downloading\n");
+       ret = check_file(fw->data);
+       if (ret < 0) {
+               brcmf_err("invalid firmware\n");
+               release_firmware(fw);
+               goto error;
+       }
+
+       devinfo = bus->bus_priv.usb->devinfo;
+       devinfo->image = fw->data;
+       devinfo->image_len = fw->size;
+
+       ret = brcmf_usb_fw_download(devinfo);
+       release_firmware(fw);
+       if (ret)
+               goto error;
+
+       ret = brcmf_usb_bus_setup(devinfo);
+       if (ret)
+               goto error;
+
+       return;
+error:
+       brcmf_dbg(TRACE, "failed: dev=%s, err=%d\n", dev_name(dev), ret);
+       device_release_driver(dev);
+}
+
 static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
 {
        struct brcmf_bus *bus = NULL;
        struct brcmf_usbdev *bus_pub = NULL;
-       int ret;
        struct device *dev = devinfo->dev;
+       int ret;
 
        brcmf_dbg(USB, "Enter\n");
        bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ);
@@ -1254,22 +1187,18 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
        bus->chip = bus_pub->devid;
        bus->chiprev = bus_pub->chiprev;
        bus->proto_type = BRCMF_PROTO_BCDC;
+       bus->always_use_fws_queue = true;
 
-       /* Attach to the common driver interface */
-       ret = brcmf_attach(dev);
-       if (ret) {
-               brcmf_err("brcmf_attach failed\n");
-               goto fail;
-       }
-
-       ret = brcmf_bus_start(dev);
-       if (ret) {
-               brcmf_err("dongle is not responding\n");
-               brcmf_detach(dev);
-               goto fail;
+       if (!brcmf_usb_dlneeded(devinfo)) {
+               ret = brcmf_usb_bus_setup(devinfo);
+               if (ret)
+                       goto fail;
        }
-
+       /* request firmware here */
+       brcmf_fw_get_firmwares(dev, 0, brcmf_usb_get_fwname(devinfo), NULL,
+                              brcmf_usb_probe_phase2);
        return 0;
+
 fail:
        /* Release resources in reverse order */
        kfree(bus);
@@ -1357,9 +1286,6 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
                goto fail;
        }
 
-       endpoint_num = endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-       devinfo->intr_pipe = usb_rcvintpipe(usb, endpoint_num);
-
        devinfo->rx_pipe = 0;
        devinfo->rx_pipe2 = 0;
        devinfo->tx_pipe = 0;
@@ -1391,16 +1317,9 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
                }
        }
 
-       /* Allocate interrupt URB and data buffer */
-       /* RNDIS says 8-byte intr, our old drivers used 4-byte */
-       if (IFEPDESC(usb, CONTROL_IF, 0).wMaxPacketSize == cpu_to_le16(16))
-               devinfo->intr_size = 8;
-       else
-               devinfo->intr_size = 4;
-
-       devinfo->interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval;
-
-       if (usb->speed == USB_SPEED_HIGH)
+       if (usb->speed == USB_SPEED_SUPER)
+               brcmf_dbg(USB, "Broadcom super speed USB wireless device detected\n");
+       else if (usb->speed == USB_SPEED_HIGH)
                brcmf_dbg(USB, "Broadcom high speed USB wireless device detected\n");
        else
                brcmf_dbg(USB, "Broadcom full speed USB wireless device detected\n");
@@ -1455,23 +1374,18 @@ static int brcmf_usb_resume(struct usb_interface *intf)
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
 
        brcmf_dbg(USB, "Enter\n");
-       if (!brcmf_attach(devinfo->dev))
-               return brcmf_bus_start(&usb->dev);
-
-       return 0;
+       return brcmf_usb_bus_setup(devinfo);
 }
 
 static int brcmf_usb_reset_resume(struct usb_interface *intf)
 {
        struct usb_device *usb = interface_to_usbdev(intf);
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
-
        brcmf_dbg(USB, "Enter\n");
 
-       if (!brcmf_usb_fw_download(devinfo))
-               return brcmf_usb_resume(intf);
-
-       return -EIO;
+       return brcmf_fw_get_firmwares(&usb->dev, 0,
+                                     brcmf_usb_get_fwname(devinfo), NULL,
+                                     brcmf_usb_probe_phase2);
 }
 
 #define BRCMF_USB_VENDOR_ID_BROADCOM   0x0a5c
@@ -1506,16 +1420,6 @@ static struct usb_driver brcmf_usbdrvr = {
        .disable_hub_initiated_lpm = 1,
 };
 
-static void brcmf_release_fw(struct list_head *q)
-{
-       struct brcmf_usb_image *fw_image, *next;
-
-       list_for_each_entry_safe(fw_image, next, q, list) {
-               vfree(fw_image->image);
-               list_del_init(&fw_image->list);
-       }
-}
-
 static int brcmf_usb_reset_device(struct device *dev, void *notused)
 {
        /* device past is the usb interface so we
@@ -1534,12 +1438,10 @@ void brcmf_usb_exit(void)
        ret = driver_for_each_device(drv, NULL, NULL,
                                     brcmf_usb_reset_device);
        usb_deregister(&brcmf_usbdrvr);
-       brcmf_release_fw(&fw_image_list);
 }
 
 void brcmf_usb_register(void)
 {
        brcmf_dbg(USB, "Enter\n");
-       INIT_LIST_HEAD(&fw_image_list);
        usb_register(&brcmf_usbdrvr);
 }