diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/usb.c')
| -rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/usb.c | 283 | 
1 files changed, 92 insertions, 191 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c index f4aea47e073..d06fcb05adf 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c @@ -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, @@ -435,7 +426,6 @@ static void brcmf_usb_rx_complete(struct urb *urb)  	struct brcmf_usbreq  *req = (struct brcmf_usbreq *)urb->context;  	struct brcmf_usbdev_info *devinfo = req->devinfo;  	struct sk_buff *skb; -	struct sk_buff_head skbq;  	brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);  	brcmf_usb_del_fromq(devinfo, req); @@ -450,10 +440,8 @@ static void brcmf_usb_rx_complete(struct urb *urb)  	}  	if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) { -		skb_queue_head_init(&skbq); -		skb_queue_tail(&skbq, skb);  		skb_put(skb, urb->actual_length); -		brcmf_rx_frames(devinfo->dev, &skbq); +		brcmf_rx_frame(devinfo->dev, skb);  		brcmf_usb_rx_refill(devinfo, req);  	} else {  		brcmu_pkt_buf_free_skb(skb); @@ -525,48 +513,15 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)  	/* update state of upper layer */  	if (state == BRCMFMAC_USB_STATE_DOWN) {  		brcmf_dbg(USB, "DBUS is down\n"); -		bcmf_bus->state = BRCMF_BUS_DOWN; +		brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DOWN);  	} else if (state == BRCMFMAC_USB_STATE_UP) {  		brcmf_dbg(USB, "DBUS is up\n"); -		bcmf_bus->state = BRCMF_BUS_DATA; +		brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DATA);  	} else {  		brcmf_dbg(USB, "DBUS current state=%d\n", 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); @@ -622,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) @@ -631,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); @@ -684,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); @@ -1024,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; @@ -1039,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); @@ -1083,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;  } @@ -1189,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"); @@ -1205,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: @@ -1225,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,24 +1184,22 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)  	bus->bus_priv.usb = bus_pub;  	dev_set_drvdata(dev, bus);  	bus->ops = &brcmf_usb_bus_ops; -	bus->chip = bus_pub->devid; -	bus->chiprev = bus_pub->chiprev; - -	/* Attach to the common driver interface */ -	ret = brcmf_attach(0, dev); -	if (ret) { -		brcmf_err("brcmf_attach failed\n"); -		goto fail; -	} +	bus->proto_type = BRCMF_PROTO_BCDC; +	bus->always_use_fws_queue = true; -	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;  	} +	bus->chip = bus_pub->devid; +	bus->chiprev = bus_pub->chiprev; +	/* 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); @@ -1359,9 +1287,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; @@ -1393,16 +1318,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"); @@ -1457,23 +1375,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(0, 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 @@ -1508,16 +1421,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 @@ -1536,12 +1439,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);  }  | 
