On Do, 2015-02-05 at 15:23 -0700, Stephen Warren wrote: > > b) In ci_bounce(), the bounce buffer is only allocated if the > user-buffer is already aligned, and if a large-enough bounce buffer > wasn't previously allocated. If ci_req->b_buf was uninitialized it could > be non-zero (thus preventing the expected aligned allocation) yet not > actually aligned enough.
I can reproduce this issue now. After some "timeout sending packets to usb ethernet" messages, the bounce buffer somehow gets corrupted. ci_bounce() is called with an unaligned input buffer length 'req->length=66', but the bounce buffer length 'ci_req->b_len=1140305940' or in hex 'ci_req->b_len=0x43f7b014'. This bounce buffer length is obviously an address, as the following misaligned error message shows: "CACHE: Misaligned operation at range [43f7b010, 43f7b070]". Both if conditions in 'align:' are not entered. This is a snippet from my debug output: timeout sending packets to usb ethernet 1: 43b7e180 - 43b7e200. req->length: 66 b_len_1: 96 b_len_2: 96 5: 43b7e660 - 43b7e6c0 timeout sending packets to usb ethernet 1: 43b7e000 - 43b7e080. req->length: 66 b_len_1: 1140305940 b_len_2: 1140305940 5: 43f7b010 - 43f7b070 CACHE: Misaligned operation at range [43f7b010, 43f7b070] timeout sending packets to usb ethernet ping failed; host 10.0.0.1 is not alive This is the corresponding code (debug number 1 and 5): static void ci_flush_qh(int ep_num) { struct ept_queue_head *head = ci_get_qh(ep_num, 0); const uint32_t start = (uint32_t)head; const uint32_t end = start + 2 * sizeof(*head); printf("1: %x - %x.\n", start, end); flush_dcache_range(start, end); } [..] static int ci_bounce(struct ci_req *ci_req, int in) { struct usb_request *req = &ci_req->req; uint32_t addr = (uint32_t)req->buf; uint32_t hwaddr; uint32_t aligned_used_len; /* Input buffer address is not aligned. */ if (addr & (ARCH_DMA_MINALIGN - 1)) { goto align; } /* Input buffer length is not aligned. */ if (req->length & (ARCH_DMA_MINALIGN - 1)) { printf("req->length: %d\n", req->length); goto align; } /* The buffer is well aligned, only flush cache. */ ci_req->hw_len = req->length; ci_req->hw_buf = req->buf; goto flush; align: printf("b_len_1: %d\n", ci_req->b_len); if (ci_req->b_buf && req->length > ci_req->b_len) { printf("A: %d - %d\n", req->length, ci_req->b_len); free(ci_req->b_buf); ci_req->b_buf = 0; } if (!ci_req->b_buf) { ci_req->b_len = roundup(req->length, ARCH_DMA_MINALIGN); ci_req->b_buf = memalign(ARCH_DMA_MINALIGN, ci_req->b_len); printf("B: %d - %d\n", req->length, ci_req->b_len); if (!ci_req->b_buf) return -ENOMEM; } ci_req->hw_len = ci_req->b_len; ci_req->hw_buf = ci_req->b_buf; printf("b_len_2: %d\n", ci_req->b_len); if (in) memcpy(ci_req->hw_buf, req->buf, req->length); flush: hwaddr = (uint32_t)ci_req->hw_buf; aligned_used_len = roundup(req->length, ARCH_DMA_MINALIGN); printf("5: %x - %x\n", hwaddr, hwaddr + aligned_used_len); flush_dcache_range(hwaddr, hwaddr + aligned_used_len); return 0; } _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot