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);