Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

zd1211rw: handle lost read-reg interrupts

Device losses read-reg interrupts. By looking at usbmon it appears that
USB_INT_ID_RETRY_FAILED can override USB_INT_ID_REGS. This causes read
command to timeout, usually under heavy TX.

Fix by retrying read registers again if USB_INT_ID_RETRY_FAILED is received
while waiting for USB_INT_ID_REGS.

However USB_INT_ID_REGS is not always lost but is received after
USB_INT_ID_RETRY_FAILED and is usually received by the retried read
command. USB_INT_ID_REGS of the retry is then left unhandled and might
be received by next read command. Handle this by ignoring previous
USB_INT_ID_REGS that doesn't match current read command request.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Jussi Kivilinna and committed by
John W. Linville
c900eff3 f762d8c3

+120 -32
+116 -31
drivers/net/wireless/zd1211rw/zd_usb.c
··· 111 111 #define FW_ZD1211_PREFIX "zd1211/zd1211_" 112 112 #define FW_ZD1211B_PREFIX "zd1211/zd1211b_" 113 113 114 + static bool check_read_regs(struct zd_usb *usb, struct usb_req_read_regs *req, 115 + unsigned int count); 116 + 114 117 /* USB device initialization */ 115 118 static void int_urb_complete(struct urb *urb); 116 119 ··· 368 365 369 366 #define urb_dev(urb) (&(urb)->dev->dev) 370 367 368 + static inline void handle_regs_int_override(struct urb *urb) 369 + { 370 + struct zd_usb *usb = urb->context; 371 + struct zd_usb_interrupt *intr = &usb->intr; 372 + 373 + spin_lock(&intr->lock); 374 + if (atomic_read(&intr->read_regs_enabled)) { 375 + atomic_set(&intr->read_regs_enabled, 0); 376 + intr->read_regs_int_overridden = 1; 377 + complete(&intr->read_regs.completion); 378 + } 379 + spin_unlock(&intr->lock); 380 + } 381 + 371 382 static inline void handle_regs_int(struct urb *urb) 372 383 { 373 384 struct zd_usb *usb = urb->context; ··· 400 383 USB_MAX_EP_INT_BUFFER); 401 384 spin_unlock(&mac->lock); 402 385 schedule_work(&mac->process_intr); 403 - } else if (intr->read_regs_enabled) { 404 - intr->read_regs.length = len = urb->actual_length; 405 - 386 + } else if (atomic_read(&intr->read_regs_enabled)) { 387 + len = urb->actual_length; 388 + intr->read_regs.length = urb->actual_length; 406 389 if (len > sizeof(intr->read_regs.buffer)) 407 390 len = sizeof(intr->read_regs.buffer); 391 + 408 392 memcpy(intr->read_regs.buffer, urb->transfer_buffer, len); 409 - intr->read_regs_enabled = 0; 393 + 394 + /* Sometimes USB_INT_ID_REGS is not overridden, but comes after 395 + * USB_INT_ID_RETRY_FAILED. Read-reg retry then gets this 396 + * delayed USB_INT_ID_REGS, but leaves USB_INT_ID_REGS of 397 + * retry unhandled. Next read-reg command then might catch 398 + * this wrong USB_INT_ID_REGS. Fix by ignoring wrong reads. 399 + */ 400 + if (!check_read_regs(usb, intr->read_regs.req, 401 + intr->read_regs.req_count)) 402 + goto out; 403 + 404 + atomic_set(&intr->read_regs_enabled, 0); 405 + intr->read_regs_int_overridden = 0; 410 406 complete(&intr->read_regs.completion); 407 + 411 408 goto out; 412 409 } 413 410 414 411 out: 415 412 spin_unlock(&intr->lock); 413 + 414 + /* CR_INTERRUPT might override read_reg too. */ 415 + if (int_num == CR_INTERRUPT && atomic_read(&intr->read_regs_enabled)) 416 + handle_regs_int_override(urb); 416 417 } 417 418 418 419 static void int_urb_complete(struct urb *urb) 419 420 { 420 421 int r; 421 422 struct usb_int_header *hdr; 423 + struct zd_usb *usb; 424 + struct zd_usb_interrupt *intr; 422 425 423 426 switch (urb->status) { 424 427 case 0: ··· 466 429 dev_dbg_f(urb_dev(urb), "error: urb %p wrong type\n", urb); 467 430 goto resubmit; 468 431 } 432 + 433 + /* USB_INT_ID_RETRY_FAILED triggered by tx-urb submit can override 434 + * pending USB_INT_ID_REGS causing read command timeout. 435 + */ 436 + usb = urb->context; 437 + intr = &usb->intr; 438 + if (hdr->id != USB_INT_ID_REGS && atomic_read(&intr->read_regs_enabled)) 439 + handle_regs_int_override(urb); 469 440 470 441 switch (hdr->id) { 471 442 case USB_INT_ID_REGS: ··· 1174 1129 spin_lock_init(&intr->lock); 1175 1130 intr->interval = int_urb_interval(zd_usb_to_usbdev(usb)); 1176 1131 init_completion(&intr->read_regs.completion); 1132 + atomic_set(&intr->read_regs_enabled, 0); 1177 1133 intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT); 1178 1134 } 1179 1135 ··· 1609 1563 return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data); 1610 1564 } 1611 1565 1612 - static void prepare_read_regs_int(struct zd_usb *usb) 1566 + static void prepare_read_regs_int(struct zd_usb *usb, 1567 + struct usb_req_read_regs *req, 1568 + unsigned int count) 1613 1569 { 1614 1570 struct zd_usb_interrupt *intr = &usb->intr; 1615 1571 1616 1572 spin_lock_irq(&intr->lock); 1617 - intr->read_regs_enabled = 1; 1573 + atomic_set(&intr->read_regs_enabled, 1); 1574 + intr->read_regs.req = req; 1575 + intr->read_regs.req_count = count; 1618 1576 INIT_COMPLETION(intr->read_regs.completion); 1619 1577 spin_unlock_irq(&intr->lock); 1620 1578 } ··· 1628 1578 struct zd_usb_interrupt *intr = &usb->intr; 1629 1579 1630 1580 spin_lock_irq(&intr->lock); 1631 - intr->read_regs_enabled = 0; 1581 + atomic_set(&intr->read_regs_enabled, 0); 1632 1582 spin_unlock_irq(&intr->lock); 1633 1583 } 1634 1584 1585 + static bool check_read_regs(struct zd_usb *usb, struct usb_req_read_regs *req, 1586 + unsigned int count) 1587 + { 1588 + int i; 1589 + struct zd_usb_interrupt *intr = &usb->intr; 1590 + struct read_regs_int *rr = &intr->read_regs; 1591 + struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer; 1592 + 1593 + /* The created block size seems to be larger than expected. 1594 + * However results appear to be correct. 1595 + */ 1596 + if (rr->length < usb_int_regs_length(count)) { 1597 + dev_dbg_f(zd_usb_dev(usb), 1598 + "error: actual length %d less than expected %d\n", 1599 + rr->length, usb_int_regs_length(count)); 1600 + return false; 1601 + } 1602 + 1603 + if (rr->length > sizeof(rr->buffer)) { 1604 + dev_dbg_f(zd_usb_dev(usb), 1605 + "error: actual length %d exceeds buffer size %zu\n", 1606 + rr->length, sizeof(rr->buffer)); 1607 + return false; 1608 + } 1609 + 1610 + for (i = 0; i < count; i++) { 1611 + struct reg_data *rd = &regs->regs[i]; 1612 + if (rd->addr != req->addr[i]) { 1613 + dev_dbg_f(zd_usb_dev(usb), 1614 + "rd[%d] addr %#06hx expected %#06hx\n", i, 1615 + le16_to_cpu(rd->addr), 1616 + le16_to_cpu(req->addr[i])); 1617 + return false; 1618 + } 1619 + } 1620 + 1621 + return true; 1622 + } 1623 + 1635 1624 static int get_results(struct zd_usb *usb, u16 *values, 1636 - struct usb_req_read_regs *req, unsigned int count) 1625 + struct usb_req_read_regs *req, unsigned int count, 1626 + bool *retry) 1637 1627 { 1638 1628 int r; 1639 1629 int i; ··· 1684 1594 spin_lock_irq(&intr->lock); 1685 1595 1686 1596 r = -EIO; 1687 - /* The created block size seems to be larger than expected. 1688 - * However results appear to be correct. 1689 - */ 1690 - if (rr->length < usb_int_regs_length(count)) { 1691 - dev_dbg_f(zd_usb_dev(usb), 1692 - "error: actual length %d less than expected %d\n", 1693 - rr->length, usb_int_regs_length(count)); 1597 + 1598 + /* Read failed because firmware bug? */ 1599 + *retry = !!intr->read_regs_int_overridden; 1600 + if (*retry) 1694 1601 goto error_unlock; 1695 - } 1696 - if (rr->length > sizeof(rr->buffer)) { 1697 - dev_dbg_f(zd_usb_dev(usb), 1698 - "error: actual length %d exceeds buffer size %zu\n", 1699 - rr->length, sizeof(rr->buffer)); 1602 + 1603 + if (!check_read_regs(usb, req, count)) { 1604 + dev_dbg_f(zd_usb_dev(usb), "error: invalid read regs\n"); 1700 1605 goto error_unlock; 1701 1606 } 1702 1607 1703 1608 for (i = 0; i < count; i++) { 1704 1609 struct reg_data *rd = &regs->regs[i]; 1705 - if (rd->addr != req->addr[i]) { 1706 - dev_dbg_f(zd_usb_dev(usb), 1707 - "rd[%d] addr %#06hx expected %#06hx\n", i, 1708 - le16_to_cpu(rd->addr), 1709 - le16_to_cpu(req->addr[i])); 1710 - goto error_unlock; 1711 - } 1712 1610 values[i] = le16_to_cpu(rd->value); 1713 1611 } 1714 1612 ··· 1709 1631 int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, 1710 1632 const zd_addr_t *addresses, unsigned int count) 1711 1633 { 1712 - int r; 1713 - int i, req_len, actual_req_len; 1634 + int r, i, req_len, actual_req_len, try_count = 0; 1714 1635 struct usb_device *udev; 1715 1636 struct usb_req_read_regs *req = NULL; 1716 1637 unsigned long timeout; 1638 + bool retry = false; 1717 1639 1718 1640 if (count < 1) { 1719 1641 dev_dbg_f(zd_usb_dev(usb), "error: count is zero\n"); ··· 1749 1671 for (i = 0; i < count; i++) 1750 1672 req->addr[i] = cpu_to_le16((u16)addresses[i]); 1751 1673 1674 + retry_read: 1675 + try_count++; 1752 1676 udev = zd_usb_to_usbdev(usb); 1753 - prepare_read_regs_int(usb); 1677 + prepare_read_regs_int(usb, req, count); 1754 1678 r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/); 1755 1679 if (r) { 1756 1680 dev_dbg_f(zd_usb_dev(usb), ··· 1776 1696 goto error; 1777 1697 } 1778 1698 1779 - r = get_results(usb, values, req, count); 1699 + r = get_results(usb, values, req, count, &retry); 1700 + if (retry && try_count < 20) { 1701 + dev_dbg_f(zd_usb_dev(usb), "read retry, tries so far: %d\n", 1702 + try_count); 1703 + goto retry_read; 1704 + } 1780 1705 error: 1781 1706 return r; 1782 1707 }
+4 -1
drivers/net/wireless/zd1211rw/zd_usb.h
··· 144 144 145 145 struct read_regs_int { 146 146 struct completion completion; 147 + struct usb_req_read_regs *req; 148 + unsigned int req_count; 147 149 /* Stores the USB int structure and contains the USB address of the 148 150 * first requested register before request. 149 151 */ ··· 171 169 void *buffer; 172 170 dma_addr_t buffer_dma; 173 171 int interval; 174 - u8 read_regs_enabled:1; 172 + atomic_t read_regs_enabled; 173 + u8 read_regs_int_overridden:1; 175 174 }; 176 175 177 176 static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr)