Hi, > I looked through the ohci-isp1362.h (thanks Dimitris for > forwarding it) and compared the register layout with the one > needed for 1160. Indeed the match is very good and it would > suffice to add the definitions of just few registers (0x2d, > 0x2e, and 0x41) to cover also 1160. Didn't make bit > comparisons of registers though. > > Lothar, a little bugfix: the macro __isp1362_clr_mask16() > currently sets rather than clears. > Thanks for that one. Usual copy/paste error. Since I still don't have any hardware to run this code on I didn't have the chance to notice it yet. :(
I've had a look through the code during the weekend and made some updates: - Depending on the hardware you have you may or may not need to split up 32 bit register accesses into two 16bit accesses to the same address. '#define CAN_USE_32BIT 0' takes care of this - fixed some typos - the read/write_buffer function takes care of buffer alignment and should handle leading/trailing bytes correctly. At least on the 1362 that has "Direct Adress" mode to access the internal buffers. I also fixed some bugs in the SL811 code: - the page wrap wasn't handled correctly Lothar Wassmann
--- linux-2.6.8.1/drivers/usb/host/ohci-isp1362.h 2004-09-13 19:26:23.000000000 +0200 +++ linux-2.6.8.1-karo/drivers/usb/host/ohci-isp1362.h 2004-09-13 15:40:46.000000000 +0200 @@ -13,7 +13,7 @@ #endif // settings used for debugging: -#define DEBUG +//#define DEBUG #ifdef DEBUG #define BUFFER_TEST #define TEST_BUF_SIZE 4096 @@ -33,7 +33,6 @@ #define REG_ACCESS_M 0x800 // reg needs to be merged with shadow reg #define REG_ACCESS_MASK 0x600 -//#define PTD_BLK_SIZE 64 #define ISP1362_BUF_SIZE 4096 #define ISP1362_REG_WRITE_OFFSET 0x80 @@ -102,13 +101,13 @@ ISP1362_REG(HCDMACFG, 0x21, REG_WIDTH_16, REG_ACCESS_RW); #define HCDMACFG_CTR_ENABLE (1 << 7) #define HCDMACFG_BURST_LEN_MASK (0x03 << 5) -#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN__MASK) +#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK) #define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0) #define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1) #define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2) #define HCDMACFG_DMA_ENABLE (1 << 4) #define HCDMACFG_BUF_TYPE_MASK (0x07 << 1) -#define HCDMACFG_BUF_TYPE(n) (((n) << 1) & HCDMACFG_BURST_LEN__MASK) +#define HCDMACFG_BUF_TYPE(n) (((n) << 1) & HCDMACFG_BUF_TYPE_MASK) #define HCDMACFG_BUF_ISTL0 HCDMACFG_BUF_TYPE(0) #define HCDMACFG_BUF_ISTL1 HCDMACFG_BUF_TYPE(1) #define HCDMACFG_BUF_INTL HCDMACFG_BUF_TYPE(2) @@ -201,6 +200,11 @@ HCHWCFG_DBWIDTH(1) | \ HCHWCFG_INT_POL | \ HCHWCFG_INT_ENABLE) + +#define HCDMACFG_INIT_VAL (HCDMACFG_BUF_DIRECT | HCDMACFG_BURST_LEN_4) + +#define CAN_USE_32BIT 1 + #else #error Specify appropriate initialization values for HW configuration registers #define HCHWCFG_INIT_VAL () @@ -280,7 +284,7 @@ int xfer_type:2; int port:1; u16 buf_addr; -// int buf_len; + int buf_len; } __attribute__((packed)); struct ptd_queue { @@ -352,53 +356,63 @@ #define hc_isp1362_data_reg (dev->data_reg) // basic access functions for ISP1362 chip registers +/* NOTE: The contents of the command register cannot read back! The driver must ensure, + * that all register accesses are performed with interrupts disabled, since the interrupt + * handler has no way of restoring the previous state. + */ static inline void HC_ISP1362_WRITE_ADDR(struct hc_isp1362_dev *dev, isp1362_reg_t reg) { //DDPRINTK("A>[EMAIL PROTECTED]", reg, (u32)hc_isp1362_addr_reg); - __asm__ volatile ("/* HC_ISP1362_WRITE_ADDR START */"); - _BUG_ON((reg & 0x80) && !(reg & REG_ACCESS_W)); + _BUG_ON((reg & ISP1362_REG_WRITE_OFFSET) && !(reg & REG_ACCESS_W)); + _BUG_ON(!irqs_disabled()); writew(reg, hc_isp1362_addr_reg); - __asm__ volatile ("/* HC_ISP1362_WRITE_ADDR END */"); } static inline void HC_ISP1362_WRITE_DATA16(struct hc_isp1362_dev *dev, u16 val) { - __asm__ volatile ("/* HC_ISP1362_WRITE_DATA16 START */"); writew(val, hc_isp1362_data_reg); - __asm__ volatile ("/* HC_ISP1362_WRITE_DATA16 END */"); } static inline u16 HC_ISP1362_READ_DATA16(struct hc_isp1362_dev *dev) { u16 val; - __asm__ volatile ("/* HC_ISP1362_READ_DATA16 START */"); + _BUG_ON(!irqs_disabled()); val = readw(hc_isp1362_data_reg); //DDPRINTK("D<[EMAIL PROTECTED]", val, (u32)hc_isp1362_data_reg); - __asm__ volatile ("/* HC_ISP1362_READ_DATA16 END */"); return val; } static inline void HC_ISP1362_WRITE_DATA32(struct hc_isp1362_dev *dev, u32 val) { - __asm__ volatile ("/* HC_ISP1362_WRITE_DATA32 START */"); + _BUG_ON(!irqs_disabled()); +#if CAN_USE_32BIT writel(val, hc_isp1362_data_reg); - __asm__ volatile ("/* HC_ISP1362_WRITE_DATA32 END */"); +#else + writew((u16)val, hc_isp1362_data_reg); + writew((u16)(val >> 16), hc_isp1362_data_reg); +#endif } static inline u32 HC_ISP1362_READ_DATA32(struct hc_isp1362_dev *dev) { u32 val; - __asm__ volatile ("/* HC_ISP1362_READ_DATA32 START */"); + _BUG_ON(!irqs_disabled()); +#if CAN_USE_32BIT val = readl(hc_isp1362_data_reg); +#else + val = (u32)readw(hc_isp1362_data_reg); + val |= (u32)readw(hc_isp1362_data_reg) << 16; +#endif //DDPRINTK("D<[EMAIL PROTECTED]", val, (u32)hc_isp1362_data_reg); - - __asm__ volatile ("/* HC_ISP1362_READ_DATA32 END */"); return val; } +// The register access routines '__isp1362_...' require interrupts to be disabled +// upon entering the routine +// The routines 'isp1362_...' disable interrupts before register access #define __isp1362_read_reg16(d, r) ({ \ u16 __v; \ _BUG_ON(((ISP1362_REG_##r) & REG_WIDTH_MASK) != REG_WIDTH_16); \ @@ -441,51 +455,6 @@ local_irq_restore(flags); \ } -#if 0 -// access functions for ISP1362 specific (16bit) registers -static inline u16 __hc_isp1362_read_reg(struct hc_isp1362_dev *dev, isp1362_reg_t reg) -{ - u16 val; - - __asm__ volatile ("/* __hc_isp1362_read_reg START */"); - _BUG_ON((reg & REG_WIDTH_MASK) != REG_WIDTH_16); - HC_ISP1362_WRITE_ADDR(dev, reg); - val = HC_ISP1362_READ_DATA16(dev); - __asm__ volatile ("/* __hc_isp1362_read_reg END */"); - return val; -} - -static inline u16 hc_isp1362_read_reg(struct hc_isp1362_dev *dev, isp1362_reg_t reg) -{ - u16 val; - unsigned long flags; - - local_irq_save(flags); - val = __hc_isp1362_read_reg(dev, reg); - local_irq_restore(flags); - - return val; -} - -static inline void __hc_isp1362_write_reg(struct hc_isp1362_dev *dev, isp1362_reg_t reg, u16 val) -{ - __asm__ volatile ("/* __hc_isp1362_write_reg START */"); - _BUG_ON((reg & REG_WIDTH_MASK) != REG_WIDTH_16); - HC_ISP1362_WRITE_ADDR(dev, reg | ISP1362_REG_WRITE_OFFSET); - HC_ISP1362_WRITE_DATA16(dev, val); - __asm__ volatile ("/* __hc_isp1362_write_reg END */"); -} - -static inline void hc_isp1362_write_reg(struct hc_isp1362_dev *dev, isp1362_reg_t reg, u16 val) -{ - unsigned long flags; - - local_irq_save(flags); - __hc_isp1362_write_reg(dev, reg, val); - local_irq_restore(flags); -} -#endif - #define __isp1362_set_mask16(d,r,m) { \ u16 __v; \ __v = __isp1362_read_reg16(dev, r); \ @@ -504,9 +473,10 @@ #define __isp1362_clr_mask16(d,r,m) { \ u16 __v; \ __v = __isp1362_read_reg16(dev, r); \ - __v |= m; \ + __v &= ~(m); \ __isp1362_write_reg16(dev, r, __v); \ } + #define isp1362_clr_mask16(d,r,m) { \ unsigned long flags; \ \ @@ -515,20 +485,58 @@ local_irq_restore(flags); \ } -static inline int __isp1362_read_buffer(struct hc_isp1362_dev *dev, void *buf, u16 offset, u16 len) +static inline void __isp1362_dma_enable(struct hc_isp1362_dev *dev, int write) +{ + __isp1362_set_mask16(dev, HCuPINT, HCuPINT_EOT); + __isp1362_set_mask16(dev, HCDMACFG, HCDMACFG_DMA_ENABLE | (write ? HCDMACFG_DMA_RW_SELECT : 0)); +} + +static inline void __isp1362_dma_disable(struct hc_isp1362_dev *dev) +{ + __isp1362_clr_mask16(dev, HCuPINT, HCuPINT_EOT); + __isp1362_clr_mask16(dev, HCDMACFG, HCDMACFG_DMA_ENABLE); +} + +static inline int __isp1362_read_buffer(struct hc_isp1362_dev *dev, void *buf, u16 offset, int len) { int ret; u8 *dp = buf; u16 data; - int i; +#if 1 + // need to check, that unaligned offset & len is ok __isp1362_write_reg32(dev, HCDIRADDR, HCDIRADDR_ADDR(offset) | HCDIRADDR_COUNT(len)); - for (i = 0; i < len - 1; i += 2) { - data = __isp1362_read_reg16(dev, HCDIRDATA); - *dp++ = data; - *dp++ = data >> 8; +#else + __isp1362_write_reg32(dev, HCDIRADDR, HCDIRADDR_ADDR(offset & ~1) | + HCDIRADDR_COUNT((len + (len & 1) + (offset & 1) & ~1)); +#endif + if (offset & 1) { + // the address within the chip buffer is not 16bit aligned + // read the first unaligned byte, then do the aligned transfer. + *dp++ = (u8)(__isp1362_read_reg16(dev, HCDIRDATA) >> 8); + len--; } - if (len & 1) { + + if (!((u32)dp & 1)) { + u16 *dp16 = (u16*)dp; + // buffer is 16bit aligned; can use 16bit aligned writes to memory + while (len > 1) { + *dp16 = __isp1362_read_reg16(dev, HCDIRDATA); + dp16++; + len -= 2; + } + dp = (u8*)dp16; + } else { + while (len > 1) { + data = __isp1362_read_reg16(dev, HCDIRDATA); + *dp++ = (u8)data; + *dp++ = (u8)(data >> 8); + len -= 2; + } + } + + WARN_ON(len & ~1); + if (len > 0) { data = __isp1362_read_reg16(dev, HCDIRDATA); *dp++ = data; } @@ -536,21 +544,54 @@ return ret; } -static inline int __isp1362_write_buffer(struct hc_isp1362_dev *dev, void *buf, u16 offset, u16 len) +static inline int __isp1362_write_buffer(struct hc_isp1362_dev *dev, void *buf, u16 offset, int len) { int ret; u8 *dp = buf; u16 data; - int i; __isp1362_write_reg32(dev, HCDIRADDR, HCDIRADDR_ADDR(offset) | HCDIRADDR_COUNT(len)); - for (i = 0; i < len - 1; i += 2) { - data = *dp++; - data = (data << 8) | *dp++; + + if (offset & 1) { + // the address within the chip buffer is not 16bit aligned + // write the first unaligned byte, then do the aligned transfer. + // In order not to disturb previously written data, we need to fetch the + // first word from the buffer and replace the high byte + data = __isp1362_read_reg16(dev, HCDIRDATA) & 0xff; + data |= *dp++; + // reset the direct address/count register + __isp1362_write_reg32(dev, HCDIRADDR, HCDIRADDR_ADDR(offset) | HCDIRADDR_COUNT(len)); + + // finally write the data word __isp1362_write_reg16(dev, HCDIRDATA, data); + + len--; } - if (len & 1) { - data = *dp++; + + if (!((u32)dp & 1)) { + u16 *dp16 = (u16*)dp; + // memory buffer is 16bit aligned; can read with word accesses + while (len > 1) { + __isp1362_write_reg16(dev, HCDIRDATA, *dp16); + dp16++; + len -= 2; + } + dp = (u8*)dp16; + } else { + // memory buffer is not 16bit aligned; must use byte access + while (len > 1) { + data = *dp++; + data = (data << 8) | *dp++; + __isp1362_write_reg16(dev, HCDIRDATA, data); + len -= 2; + } + } + + WARN_ON(len & ~1); + if (len > 0) { + // finally write any trailing byte; we don't need to care about the high byte of + // the last word written + data = (u16)*dp++; __isp1362_write_reg16(dev, HCDIRDATA, data); } @@ -596,4 +637,4 @@ #endif // function prototypes -static __inline void retire_td(struct usb_hcd *hcd, struct td *td, struct ed *ed); +static __inline void retire_td(struct usb_hcd *hcd, struct td *td, struct ed *ed, u32 cc); --- linux-2.6.8.1/drivers/usb/host/ohci-sl811-emu.c 2004-09-13 18:56:15.000000000 +0200 +++ linux-2.6.8.1-karo/drivers/usb/host/ohci-sl811-emu.c 2004-09-13 19:09:24.000000000 +0200 @@ -16,6 +16,8 @@ #include <asm/arch/dma.h> +#define MULT_CTRL + #define get_hw_fld(p,n) le32_to_cpu((p)->hw##n) #define set_hw_fld(p,n,v) (p)->hw##n = cpu_to_le32(v) #define get_hwinfo(p) get_hw_fld(p, INFO) @@ -32,25 +34,27 @@ #define TD_FC_GET(info) (((info) >> 24) & 7) #define TD_SF_GET(info) (((info) >> 0) & 0xffff) -static u32 TD_BUF_LEN(struct td *td) +static inline u32 BUF_LEN(u32 cbp, u32 be) { - u32 len = 0; - u32 cbp = get_hw_fld(td, CBP); + u32 len; - if (cbp != 0) { - u32 be = get_hw_fld(td, BE); + if (cbp == 0) { + return 0; + } - if (unlikely((cbp ^ be) & PAGE_MASK)) { - // CBP and BE in different pages - // length till end of first page + length in second page - len = (PAGE_SIZE - (cbp & ~PAGE_MASK)) + (be & ~PAGE_MASK) + 1; - } else { - len = be - cbp + 1; - } + if (unlikely((cbp ^ be) & PAGE_MASK)) { + // CBP and BE in different pages + // length till end of first page + length in second page + len = (PAGE_SIZE - (cbp & ~PAGE_MASK)) + (be & ~PAGE_MASK) + 1; + } else { + len = be - cbp + 1; } + BUG_ON(len > 2 * PAGE_SIZE); return len; } +#define TD_BUF_LEN(td) BUF_LEN(get_hw_fld(td, CBP), get_hw_fld(td, BE)) + #define ED_MPS (((1 << 10) - 1) << 16) #define ed_pid(info) (((info) & (ED_IN | ED_OUT)) >> 11) @@ -68,13 +72,9 @@ static inline u32 DMA_XFER_SIZE(u32 addr, u32 len) { - u32 count = len; + u32 max_count = PAGE_SIZE - (addr & ~PAGE_MASK); - if (unlikely(((addr & ~PAGE_MASK) + len) > PAGE_SIZE)) { - count = PAGE_ALIGN(addr + len) - addr; - } - - return count; + return len > max_count ? max_count : len; } #define OHCI_FR ((1 << 14) - 1) @@ -98,8 +98,8 @@ unsigned int time; unsigned int available = update_fm_remaining(ohci); struct ohci_regs *regs = ohci->regs; - struct usb_hcd *hcd = ohci_to_hcd(ohci); - struct hc_sl811_dev *dev = hcd_to_sl811_dev(hcd); + //struct usb_hcd *hcd = ohci_to_hcd(ohci); + //struct hc_sl811_dev *dev = hcd_to_sl811_dev(hcd); if (ed_flags & ED_LOWSPEED) { if (available < HcLsThreshold) { @@ -135,37 +135,78 @@ } } +static u32 update_cbp(u32 cbp, u32 be, u32 len) +{ + unsigned int chunk_size = DMA_XFER_SIZE(cbp, len); + + BUG_ON(chunk_size > len); + BUG_ON(chunk_size > BUF_LEN(cbp, be)); + + if (likely(chunk_size == len)) { + // all data fits in current page + cbp += len; + } else { + // data extends into next page + cbp = (be & PAGE_MASK) + (len - chunk_size); + } + if (cbp - 1 == be) { + // all data has been transferred for this TD + cbp = 0; + } + + return cbp; +} + static void sl811_dma_recv_data(struct hc_sl811_dev *dev, struct xfer_buf *buf, u8 offset) { struct usb_hcd *hcd = hc_sl811_dev_to_hcd(dev); + dma_addr_t dma_addr = buf->dma_addr; + int len = buf->count; - if (buf->count == 0) { - // nothing to to, if no transfer buffer given - return; - } + BUG_ON(len > buf->buf_len || len > (SL811_BUF_SIZE / FLIP_BUFFERS)); + + WARN_ON((dma_addr == 0) ^ (len == 0)); + while (len > 0) { + u32 dma_size = DMA_XFER_SIZE(dma_addr, len); + void *buf_addr = (void*)dma_to_virt(hcd->self.controller, dma_addr); - BUG_ON(buf->count > buf->buf_len || buf->count > (SL811_BUF_SIZE / FLIP_BUFFERS)); - BUG_ON(buf->buf_addr == NULL); + __hc_sl811_read_regs(dev, offset, buf_addr, dma_size); + dma_sync_single_for_device(hcd->self.controller, dma_addr, dma_size, DMA_TO_DEVICE); - __hc_sl811_read_regs(dev, offset, buf->buf_addr, buf->count); - dma_sync_single_for_cpu(hcd->self.controller, get_hw_fld(buf->td, CBP), buf->count, - DMA_TO_DEVICE); + if (len == dma_size) { + len = 0; + } else { + dma_addr = get_hw_fld(buf->td, BE) & PAGE_MASK; + len -= dma_size; + offset += dma_size; + } + } } static void sl811_dma_send_data(struct hc_sl811_dev *dev, struct xfer_buf *buf, u8 offset) { struct usb_hcd *hcd = hc_sl811_dev_to_hcd(dev); + dma_addr_t dma_addr = buf->dma_addr; + int len = buf->len; - if (buf->len == 0) { - // nothing to to, if no transfer buffer given - return; - } + BUG_ON(len > buf->buf_len || len > (SL811_BUF_SIZE / FLIP_BUFFERS)); + + WARN_ON((dma_addr == 0) ^ (len == 0)); + while (len > 0) { + u32 dma_size = DMA_XFER_SIZE(dma_addr, len); + void *buf_addr = (void*)dma_to_virt(hcd->self.controller, dma_addr); - BUG_ON(buf->len > buf->buf_len || buf->len > (SL811_BUF_SIZE / FLIP_BUFFERS)); + dma_sync_single_for_cpu(hcd->self.controller, dma_addr, dma_size, DMA_FROM_DEVICE); + __hc_sl811_write_regs(dev, offset, buf_addr, dma_size); - dma_sync_single_for_cpu(hcd->self.controller, get_hw_fld(buf->td, CBP), buf->len, - DMA_FROM_DEVICE); - __hc_sl811_write_regs(dev, offset, buf->buf_addr, buf->len); + if (len == dma_size) { + len = 0; + } else { + dma_addr = get_hw_fld(buf->td, BE) & PAGE_MASK; + len -= dma_size; + offset += dma_size; + } + } } static int start_xfer(struct usb_hcd *hcd, struct hc_sl811_dev *dev, int flip) @@ -193,11 +234,11 @@ BUG_ON(buf_offs + buf->len > SL811_BUF_SIZE); BUG_ON(buf->len > (SL811_BUF_SIZE / FLIP_BUFFERS)); - if (buf->hc & SL11H_HCTLMASK_WRITE && buf->len > 0) { + if ((buf->hc & SL11H_HCTLMASK_WRITE) && (buf->len > 0)) { // transfer data from TD buffer to SL811 buffer memory - BUG_ON(buf->buf_addr == NULL); + BUG_ON(buf->dma_addr == 0); ohci_vdbg(hcd_to_ohci(hcd), "%s: Transferring %d of %d byte from %08x to %02x\n", - __FUNCTION__, buf->len, buf->buf_len, (u32)buf->buf_addr, + __FUNCTION__, buf->len, buf->buf_len, buf->dma_addr, SL11H_DATA_START + buf_offs); sl811_dma_send_data(dev, buf, SL11H_DATA_START + buf_offs); } @@ -241,15 +282,8 @@ if (dev->current_td == NULL) { dev->current_td = td; - - if (td->hwCBP != 0) { - dev->buf_addr = (void*)dma_to_virt(hcd->self.controller, - get_hw_fld(td, CBP)); - dev->buf_len = TD_BUF_LEN(td); - } else { - dev->buf_addr = NULL; - dev->buf_len = 0; - } + dev->dma_addr = get_hw_fld(td, CBP); + dev->buf_len = TD_BUF_LEN(td); } pid = ed_td_to_pid[ed_pid(ed_flags)][td_pid(td_flags)]; @@ -286,7 +320,7 @@ len = dev->buf_len; } - buf->buf_addr = dev->buf_addr; + buf->dma_addr = dev->dma_addr; buf->buf_len = dev->buf_len; buf->hc = hc_flags; @@ -297,11 +331,11 @@ if (start_xfer(hcd, dev, flip)) { if (dev->buf_len > len) { - dev->buf_addr += len; + dev->dma_addr = update_cbp(dev->dma_addr, get_hw_fld(td, BE), len); dev->buf_len -= len; } else { dev->buf_len = 0; - dev->buf_addr = NULL; + dev->dma_addr = 0; } } @@ -365,16 +399,23 @@ td = find_td(ohci, dev, ed); } - if ((td && (ed_flags & ED_LOWSPEED) && (rem < HcLsThreshold)) || - ((td == dev->current_td) && (dev->buf_len == 0))) { - td = NULL; - ret = 1; + if (td == NULL) { + continue; + } + if (ed_flags & ED_ISO) { + // operation not supported, fail with -EIO + printk("%s: ISO transfers not supported\n", __FUNCTION__); + retire_td(hcd, td, ed, 0x0a); + continue; } - if (td != NULL) { - done = process_td(ohci, td, flip); - ret = done; + if (((ed_flags & ED_LOWSPEED) && (rem < HcLsThreshold)) || + ((td == dev->current_td) && (dev->buf_len == 0))) { + ret = 1; + continue; } + done = process_td(ohci, td, flip); + ret |= done; } return ret; @@ -407,10 +448,12 @@ } // process ctrl EDs until cbsr limit reached if ((HcControl & OHCI_CTRL_CLE) && (dev->cbc <= cbsr)) { +#ifdef MULT_CTRL if ((HcControlCurrentED == 0) && (HcCmdStatus & OHCI_CLF)) { HcControlCurrentED = HcControlHeadED; HcCmdStatus &= ~OHCI_CLF; } +#endif if (HcControlCurrentED != 0) { ret = process_ed_list(ohci, &HcControlCurrentED, flip); if (ret > 0) { @@ -494,9 +537,8 @@ return ret; } -static u32 retire_td(struct usb_hcd *hcd, struct td *td, struct ed *ed, u32 cc) +static void retire_td(struct usb_hcd *hcd, struct td *td, struct ed *ed, u32 cc) { - u32 ohci_int_status = 0; struct hc_sl811_dev *dev = hcd_to_sl811_dev(hcd); struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct ohci_regs *regs = ohci->regs; @@ -506,13 +548,14 @@ u32 int_delay = (cc == TD_CC_NOERROR) ? (td_flags & TD_DI) >> 21 : 0; u32 ed_halt = 0; - BUG_ON(TD_CC_GET(td_flags) != TD_NOTACCESSED); + WARN_ON(TD_CC_GET(td_flags) != TD_NOTACCESSED); if (dev->current_td == td) { dev->current_td = NULL; } - ohci_dbg(ohci, "%s: Retiring TD %08x of ED %08x\n", __FUNCTION__, (u32)td, (u32)ed); + ohci_vdbg(ohci, "%s: Retiring TD %08x of ED %08x with CC=%d\n", __FUNCTION__, (u32)td, + (u32)ed, cc); if (dev->num_bufs > 1) { WARN_ON(1); kill_xfer_bufs(hcd, dev, td); @@ -522,7 +565,7 @@ if (!(ed_flags & ED_ISO)) { ed_halt = (cc != TD_CC_NOERROR) ? cpu_to_le32(ED_H) : 0; if (ed_halt) { - ohci_dbg(ohci, "%s: ED %08x (TD %08x) Halted due to error: %d\n", + ohci_vdbg(ohci, "%s: ED %08x (TD %08x) Halted due to error: %d\n", __FUNCTION__, (u32)ed, (u32)td, cc); } ed_halt |= ((td_flags & TD_T) == TD_T_DATA1) ? cpu_to_le32(ED_C) : 0; @@ -530,13 +573,11 @@ ed->hwHeadP = td->hwNextTD | ed_halt; td->hwNextTD = HcDoneHead; - HcDoneHead = td_dma; + HcDoneHead = cpu_to_le32(td_dma); if ((int_delay != 7) && (int_delay < dev->intrdelay)) { dev->intrdelay = int_delay; } - - return ohci_int_status; } static void update_data_toggle(struct usb_hcd *hcd, struct td *td) @@ -579,40 +620,11 @@ return ret; } -static int update_cbp(struct td *td, int len) -{ - u32 cbp = get_hw_fld(td, CBP); - u32 be = get_hw_fld(td, BE); - int finished = 0; - - if (cbp == 0) { - return 1; - } - - if (TD_BUF_LEN(td) == len) { - cbp = 0; - finished = 1; - } else { - u32 chunk_size = DMA_XFER_SIZE(cbp, len); - - if (chunk_size == len) { - cbp += len; - } else { - cbp = (be & ~PAGE_MASK) | (len - chunk_size); - } - WARN_ON(cbp > be); - } - set_hw_fld(td, CBP, cbp); - - return finished; -} - #define TD_EC_GET(info) (((info) & TD_EC) >> 26) #define TD_EC_SET_HW(td, ec) set_hwinfo(td, (get_hwinfo(td) & ~TD_EC) | (((ec) << 26) & TD_EC)) -static u32 update_td_status(struct usb_hcd *hcd, struct xfer_buf *buf, struct td *td) +static void update_td_status(struct usb_hcd *hcd, struct xfer_buf *buf, struct td *td) { - u32 ohci_int_status = 0; struct ed *ed = td->ed; struct hc_sl811_dev *dev = hcd_to_sl811_dev(hcd); u32 td_flags = get_hwinfo(td); @@ -623,8 +635,6 @@ int td_halt = 0; u32 cc = TD_CC_NOERROR; - BUG_ON(iso); - WARN_ON(TD_CC_GET(td_flags) != TD_NOTACCESSED); if (unlikely((pkt_stat & SL811_PKT_ERR_MASK) != 0)) { @@ -635,11 +645,11 @@ if (dev->num_bufs > 1) { kill_xfer_bufs(hcd, dev, td); } - return 0; + return; } td_halt = 1; if (pkt_stat & SL11H_STATMASK_STALL) { - ohci_dbg(hcd_to_ohci(hcd), "%s: Got STALL on TD %08x of ED %08x\n", + ohci_vdbg(hcd_to_ohci(hcd), "%s: Got STALL on TD %08x of ED %08x\n", __FUNCTION__, (u32)td, (u32)ed); cc = TD_CC_STALL; } else if (pkt_stat & (SL11H_STATMASK_TMOUT | @@ -647,8 +657,6 @@ SL11H_STATMASK_SEQ)) { int err_count = TD_EC_GET(td_flags) + 1; - ohci_dbg(hcd_to_ohci(hcd), "%s: XMIT ERROR on TD %08x of ED %08x\n", __FUNCTION__, - (u32)td, (u32)ed); if (pkt_stat & SL11H_STATMASK_TMOUT) { cc = TD_DEVNOTRESP; } else if (pkt_stat & SL11H_STATMASK_SEQ) { @@ -664,46 +672,36 @@ if (dev->num_bufs > 1) { kill_xfer_bufs(hcd, dev, td); } - return 0; + return; } + ohci_dbg(hcd_to_ohci(hcd), "%s: XMIT ERROR %d on TD %08x of ED %08x\n", + __FUNCTION__, cc, (u32)td, (u32)ed); } else if (pkt_stat & SL11H_STATMASK_OVF) { cc = TD_DATAOVERRUN; + ohci_warn(hcd_to_ohci(hcd), "%s: Data overrun: pkt_stat: %02x\n", + __FUNCTION__, pkt_stat); + } } else if (pkt_stat & SL11H_STATMASK_ACK) { - ohci_dbg(hcd_to_ohci(hcd), "%s: Got ACK on TD %08x of ED %08x\n", __FUNCTION__, - (u32)td, (u32)ed); + u32 cbp = get_hw_fld(td, CBP); - if (buf->count > TD_BUF_LEN(td)) { - ohci_warn(hcd_to_ohci(hcd), - "%s: Data overrun: bufsize: %04x datasize: %04x\n", __FUNCTION__, - TD_BUF_LEN(td), buf->count); - cc = TD_DATAOVERRUN; - goto err; - } + ohci_vdbg(hcd_to_ohci(hcd), "%s: Got ACK on TD %08x of ED %08x\n", __FUNCTION__, + (u32)td, (u32)ed); TD_EC_SET_HW(td, 0); - td_finished = update_cbp(td, buf->count); - + cbp = update_cbp(cbp, get_hw_fld(td, BE), buf->count); + set_hw_fld(td, CBP, cbp); + td_finished = cbp == 0; if (!td_finished && (buf->count < ed_mps(ed_flags))) { - u32 cbp = get_hw_fld(td, CBP); - u32 be = get_hw_fld(td, BE); - - if (!(td_flags & TD_R) || (buf->count == 0)) { + if (!(td_flags & TD_R)) { td_halt = 1; ohci_warn(hcd_to_ohci(hcd), "%s: Data underrun: %d byte transferred, %d byte requested\n", - __FUNCTION__, buf->count, ed_mps(ed_flags)); + __FUNCTION__, buf->count, ed_mps(ed_flags)); cc = TD_DATAUNDERRUN; goto err; } - if ((be & PAGE_MASK) == ((cbp + buf->count - 1) & PAGE_MASK)) { - be = cbp + buf->count - 1; - } else { - be = (be & ~PAGE_MASK) + ((cbp + buf->count - 1) & ~PAGE_MASK); - } - set_hw_fld(td, BE, be); - set_hw_fld(td, CBP, 0); td_finished = 1; } } else { @@ -712,11 +710,9 @@ } if (pkt_stat & SL11H_STATMASK_ACK) { - if (buf->buf_len > FLIP_BUFFERS * buf->count) { - buf->buf_len -= FLIP_BUFFERS * buf->count; - buf->buf_addr += FLIP_BUFFERS * buf->count; + if (buf->buf_len > buf->count) { + buf->buf_len -= buf->count; } else { - buf->buf_addr = NULL; buf->buf_len = 0; } if (buf->len > buf->buf_len) { @@ -730,30 +726,24 @@ err: if (td_finished || (td_halt && !iso)) { - ohci_int_status |= retire_td(hcd, td, ed, cc); + retire_td(hcd, td, ed, cc); } - - return ohci_int_status; } -static u32 kill_current_td(struct usb_hcd *hcd, struct hc_sl811_dev *dev) +static void kill_current_td(struct usb_hcd *hcd, struct hc_sl811_dev *dev) { struct td *td = dev->current_td; - u32 ohci_int_status = 0; BUG_ON(td == NULL); kill_xfer_bufs(hcd, dev, td); ohci_warn(hcd_to_ohci(hcd), "%s: killing TD %08x (ED: %08x)\n", __FUNCTION__, (u32)td, (u32)td->ed); - ohci_int_status |= retire_td(hcd, td, td->ed, TD_DEVNOTRESP); - - return ohci_int_status; + retire_td(hcd, td, td->ed, TD_DEVNOTRESP); } -static u32 finish_xfer(struct usb_hcd *hcd, struct hc_sl811_dev *dev, int flip) +static void finish_xfer(struct usb_hcd *hcd, struct hc_sl811_dev *dev, int flip) { - u32 ohci_int_status = 0; struct xfer_buf *buf = &dev->xfer_buf[flip]; struct td *td = buf->td; int reg_offs = flip * 8; @@ -764,6 +754,13 @@ __hc_sl811_read_regs(dev, SL11H_PKTSTATREG + reg_offs, &buf->rcv_data, sizeof(buf->rcv_data)); buf->count = buf->len - buf->count; + if (buf->count > TD_BUF_LEN(td)) { + ohci_warn(hcd_to_ohci(hcd), + "%s: Data overrun: bufsize: %04x datasize: %04x\n", __FUNCTION__, + TD_BUF_LEN(td), buf->count); + retire_td(hcd, td, td->ed, TD_DATAOVERRUN); + return; + } if (!(buf->hc & SL11H_HCTLMASK_WRITE)) { if (check_data_toggle(td, buf, hcd)) { buf->pkt_stat &= ~SL11H_STATMASK_SEQ; @@ -781,24 +778,20 @@ if (buf->count > 0) { ohci_vdbg(hcd_to_ohci(hcd), "%s: Transferring %d of %d byte from %02x to %08x\n", - __FUNCTION__, buf->count, buf->buf_len, offset, - (u32)buf->buf_addr); - BUG_ON(TD_BUF_LEN(td) == 0); + __FUNCTION__, buf->count, buf->buf_len, offset, buf->dma_addr); sl811_dma_recv_data(dev, buf, SL11H_DATA_START + buf_offs); } } } else { buf->pkt_stat &= ~SL11H_STATMASK_SEQ; } - ohci_int_status = update_td_status(hcd, buf, td); + update_td_status(hcd, buf, td); } dev->num_bufs--; BUG_ON(dev->num_bufs > FLIP_BUFFERS); dev->buf_map &= ~(1 << flip); buf->td = NULL; - - return ohci_int_status; } /* @@ -855,7 +848,7 @@ u8 svc_mask; int_status = __hc_sl811_read_reg(dev, SL11H_INTSTATREG); - BUG_ON((FLIP_BUFFERS == 1) && (int_status & SL11H_INTMASK_XFERDONE_B)); + WARN_ON((FLIP_BUFFERS == 1) && (int_status & SL11H_INTMASK_XFERDONE_B)); svc_mask = int_status & int_mask; if (handled && (svc_mask == 0)) { break; @@ -877,6 +870,7 @@ handled = 0x80000000; __hc_sl811_write_reg(dev, SL11H_INTSTATREG, svc_mask & ~(SL11H_INTMASK_RESUME|SL11H_INTMASK_INSRMV)); + if (svc_mask & SL11H_INTMASK_INSRMV) { svc_mask &= ~SL11H_INTMASK_INSRMV; int_mask &= ~SL11H_INTMASK_INSRMV; @@ -886,7 +880,7 @@ dev->dev_state &= ~(DEV_ACTIVE | DEV_SOF); if (dev->current_td) { - ohci_int_status |= kill_current_td(hcd, dev); + kill_current_td(hcd, dev); ohci_int_status |= OHCI_INTR_SF; } @@ -967,7 +961,7 @@ int soc = (HcCmdStatus - OHCI_SOC) & OHCI_SOC; if (dev->current_td) { - ohci_int_status |= kill_current_td(hcd, dev); + kill_current_td(hcd, dev); } ohci_warn(ohci, "%s: Scheduling overrun at frame %04x\n", @@ -1040,7 +1034,7 @@ svc_mask &= ~im; handled |= im; - ohci_int_status |= finish_xfer(hcd, dev, flip); + finish_xfer(hcd, dev, flip); if (dev->dev_state & DEV_SOF) { if (dev->current_td && dev->buf_len > 0) { process_td(ohci, dev->current_td, flip); @@ -1070,8 +1064,8 @@ if (ohci_int_status != 0) { HcIntrStatus |= ohci_int_status; if ((HcIntrEnable & OHCI_INTR_MIE) && (ohci_int_status & HcIntrEnable)) { - ohci_dbg(ohci, "%s: Calling OHCI interrupt handler: %08x(%08x):%08x\n", - __FUNCTION__, HcIntrStatus, ohci_int_status, HcIntrEnable); + ohci_vdbg(ohci, "%s: Calling OHCI interrupt handler: %08x(%08x):%08x\n", + __FUNCTION__, HcIntrStatus, ohci_int_status, HcIntrEnable); // call the OHCI IRQ handler if (usb_hcd_irq(hcd->irq, hcd, pt_regs) != IRQ_HANDLED) { ohci_warn(ohci, "%s: Spurious OHCI Interrupt: %08x(%08x):%08x\n", --- linux-2.6.8.1/drivers/usb/host/ohci-sl811.c 2004-09-13 18:56:15.000000000 +0200 +++ linux-2.6.8.1-karo/drivers/usb/host/ohci-sl811.c 2004-09-13 19:09:24.000000000 +0200 @@ -442,6 +442,15 @@ local_irq_restore(flags); } +static void usb_hcd_sl811_release(struct usb_bus *bus) +{ + struct usb_hcd *hcd = bus->hcpriv; + + if (hcd != NULL) { + hcd->driver->hcd_free(hcd); + } +} + /** * usb_hcd_sl811_probe - initialize HC-SL811-based HCDs * Context: !in_interrupt() @@ -452,8 +461,7 @@ * * Store this function in the HCD's struct pci_driver as probe(). */ -static int usb_hcd_sl811_probe(struct hc_driver *driver, struct usb_hcd **hcd_out, - struct hc_sl811_dev *dev) +static int usb_hcd_sl811_probe(struct hc_driver *driver, struct hc_sl811_dev *dev) { int retval; struct usb_hcd *hcd = NULL; @@ -515,6 +523,8 @@ usb_bus_init(&hcd->self); hcd->self.op = &usb_hcd_operations; hcd->self.hcpriv = hcd; + hcd->self.release = usb_hcd_sl811_release; + init_timer(&hcd->rh_timer); INIT_LIST_HEAD(&hcd->dev_list); @@ -530,8 +540,6 @@ info("%s (HC-%s) at 0x%p, irq %d\n", hcd->description, chip_names[dev->hw_rev & 0x0f], hcd->regs, hcd->irq); - *hcd_out = hcd; - return 0; err3: @@ -587,8 +595,6 @@ usb_deregister_bus(&hcd->self); - hcd->driver->hcd_free(hcd); - return 0; } @@ -802,7 +808,7 @@ goto out; } - ret = usb_hcd_sl811_probe(&ohci_sl811_hc_driver, &hcd, dev); + ret = usb_hcd_sl811_probe(&ohci_sl811_hc_driver, dev); if (ret == 0) { return ret; } @@ -851,47 +857,6 @@ return 0; } -static void __sl811_release(struct device *dev) -{ - struct hc_sl811_dev *sl811_dev = dev_get_drvdata(dev); - - printk("%s: dev=%08x\n", __FUNCTION__, (u32)dev); - if (sl811_dev != NULL) { - kfree(sl811_dev); - } -} - -#define MALLOC_SIZE sizeof(struct hc_sl811_dev) -static int __sl811_probe(struct device *dev, struct resource *mem, struct resource *irq) -{ - int ret; - struct hc_sl811_dev *sl811_dev; - - sl811_dev = kmalloc(MALLOC_SIZE, GFP_KERNEL); - if (sl811_dev == NULL) { - return -ENOMEM; - } - memset(sl811_dev, 0, MALLOC_SIZE); - - sl811_dev->irq = NO_IRQ; - - sl811_dev->dev.parent = dev; - sl811_dev->dev.bus = &platform_bus_type; - sl811_dev->dev.release = __sl811_release; - - //spin_lock_init(&sl811_dev->irq_lock); - - dev_set_drvdata(dev, sl811_dev); - - ret = ohci_hcd_sl811_drv_probe(sl811_dev); - - if (ret != 0) { - dev_set_drvdata(dev, NULL); - } - - return ret; -} - static int usb_hcd_sl811_suspend(struct hc_sl811_dev *dev, u32 state) { struct usb_hcd *hcd; @@ -975,31 +940,41 @@ return retval; } -static struct hc_sl811_driver ohci_hcd_sl811_driver = { - .drv = { - .name = "sl811-ohci", - .bus = &platform_bus_type, - }, - .devid = 0, - .probe = ohci_hcd_sl811_drv_probe, - .remove = ohci_hcd_sl811_drv_remove, -#ifdef CONFIG_PM - .suspend = usb_hcd_sl811_suspend, - .resume = usb_hcd_sl811_resume, -#endif -}; +static void sl811_bus_release(struct device *dev) +{ + struct hc_sl811_dev *sl811_dev = dev_get_drvdata(dev); + + printk("%s: dev=%08x\n", __FUNCTION__, (u32)dev); + if (sl811_dev != NULL) { + kfree(sl811_dev); + } +} static int sl811_bus_probe(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct resource *mem, *irq = NULL; - int ret = -ENODEV; - - mem = &pdev->resource[0]; - if (pdev->num_resources == 2) { - irq = &pdev->resource[1]; + int ret = 0; + struct hc_sl811_dev *sl811_dev; + struct hc_sl811_driver *drv = SL811_DRV(dev->driver); + + sl811_dev = kmalloc(sizeof(struct hc_sl811_dev), GFP_KERNEL); + if (sl811_dev == NULL) { + return -ENOMEM; + } + memset(sl811_dev, 0, sizeof(struct hc_sl811_dev)); + + sl811_dev->irq = NO_IRQ; + + sl811_dev->dev.parent = dev; + sl811_dev->dev.bus = &platform_bus_type; + sl811_dev->dev.release = sl811_bus_release; + + dev_set_drvdata(dev, sl811_dev); + if (drv->probe) { + ret = drv->probe(sl811_dev); + if (ret != 0) { + dev_set_drvdata(dev, NULL); + } } - ret = __sl811_probe(dev, mem, irq); return ret; } @@ -1041,15 +1016,29 @@ return ret; } +static struct hc_sl811_driver ohci_hcd_sl811_driver = { + .drv = { + .name = "sl811-ohci", + .bus = &platform_bus_type, + .probe = sl811_bus_probe, + .remove = sl811_bus_remove, + .suspend = sl811_bus_suspend, + .resume = sl811_bus_resume, + }, + .devid = 0, + .probe = ohci_hcd_sl811_drv_probe, + .remove = ohci_hcd_sl811_drv_remove, +#ifdef CONFIG_PM + .suspend = usb_hcd_sl811_suspend, + .resume = usb_hcd_sl811_resume, +#endif +}; + static int hc_sl811_driver_register(struct hc_sl811_driver *driver) { int ret; - WARN_ON(driver->drv.suspend || driver->drv.resume || driver->drv.probe || driver->drv.remove); - driver->drv.probe = sl811_bus_probe; - driver->drv.remove = sl811_bus_remove; - driver->drv.suspend = sl811_bus_suspend; - driver->drv.resume = sl811_bus_resume; + WARN_ON(!driver->drv.suspend || !driver->drv.resume || !driver->drv.probe || !driver->drv.remove); ret = driver_register(&driver->drv); --- linux-2.6.8.1/drivers/usb/host/ohci-sl811.h 2004-09-13 18:56:15.000000000 +0200 +++ linux-2.6.8.1-karo/drivers/usb/host/ohci-sl811.h 2004-09-13 19:09:24.000000000 +0200 @@ -14,7 +14,9 @@ * */ +#ifdef CONFIG_ARCH_KARO #include <asm/arch/karo.h> +#endif //#define USE_DMA //Can't use DMA because of SL811 register address alignment :( #define FLIP_BUFFERS 1 @@ -134,7 +136,7 @@ #define DEV_TRIGGERED (DEV_CONN_CHK | DEV_OHCI_IRQ) struct xfer_buf { - void *buf_addr; + dma_addr_t dma_addr; int buf_len; struct td *td; union { @@ -165,7 +167,8 @@ struct tasklet_struct usb_reset_bh; struct xfer_buf xfer_buf[FLIP_BUFFERS]; unsigned int flip; - void *buf_addr; + dma_addr_t dma_addr; + //void *buf_addr; int buf_len; unsigned int num_bufs; unsigned int buf_map; @@ -347,5 +350,5 @@ static void hc_sl811_usb_reset(struct usb_hcd *hcd, int assert); static void hc_sl811_start_sof(struct usb_hcd *hcd, int lowspeed); static void ohci_sl811_bh(unsigned long data); -static u32 retire_td(struct usb_hcd *hcd, struct td *td, struct ed *ed, u32 cc); -static u32 kill_current_td(struct usb_hcd *hcd, struct hc_sl811_dev *dev); +static void retire_td(struct usb_hcd *hcd, struct td *td, struct ed *ed, u32 cc); +static void kill_current_td(struct usb_hcd *hcd, struct hc_sl811_dev *dev);