|
@@ -103,16 +103,91 @@ static struct pci_device_id ehci_pci_ids[] = {
|
|
|
# define m32_swap(x) cpu_to_le32(x)
|
|
|
#endif /* CONFIG_SYS_OHCI_BE_CONTROLLER */
|
|
|
|
|
|
+#ifdef CONFIG_DM_USB
|
|
|
+/*
|
|
|
+ * We really should do proper cache flushing everywhere, but for now we only
|
|
|
+ * do it for new (driver-model) usb code to avoid regressions.
|
|
|
+ */
|
|
|
+#define flush_dcache_buffer(addr, size) \
|
|
|
+ flush_dcache_range((unsigned long)(addr), \
|
|
|
+ ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
|
|
|
+#define invalidate_dcache_buffer(addr, size) \
|
|
|
+ invalidate_dcache_range((unsigned long)(addr), \
|
|
|
+ ALIGN((unsigned long)(addr) + size, ARCH_DMA_MINALIGN))
|
|
|
+#else
|
|
|
+#define flush_dcache_buffer(addr, size)
|
|
|
+#define invalidate_dcache_buffer(addr, size)
|
|
|
+#endif
|
|
|
+
|
|
|
+/* Do not use sizeof(ed / td) as our ed / td structs contain extra members */
|
|
|
+#define flush_dcache_ed(addr) flush_dcache_buffer(addr, 16)
|
|
|
+#define flush_dcache_td(addr) flush_dcache_buffer(addr, 16)
|
|
|
+#define flush_dcache_iso_td(addr) flush_dcache_buffer(addr, 32)
|
|
|
+#define flush_dcache_hcca(addr) flush_dcache_buffer(addr, 256)
|
|
|
+#define invalidate_dcache_ed(addr) invalidate_dcache_buffer(addr, 16)
|
|
|
+#define invalidate_dcache_td(addr) invalidate_dcache_buffer(addr, 16)
|
|
|
+#define invalidate_dcache_iso_td(addr) invalidate_dcache_buffer(addr, 32)
|
|
|
+#define invalidate_dcache_hcca(addr) invalidate_dcache_buffer(addr, 256)
|
|
|
+
|
|
|
/* global ohci_t */
|
|
|
static ohci_t gohci;
|
|
|
/* this must be aligned to a 256 byte boundary */
|
|
|
struct ohci_hcca ghcca[1];
|
|
|
-/* a pointer to the aligned storage */
|
|
|
-struct ohci_hcca *phcca;
|
|
|
-/* this allocates EDs for all possible endpoints */
|
|
|
-struct ohci_device ohci_dev;
|
|
|
-/* device which was disconnected */
|
|
|
-struct usb_device *devgone;
|
|
|
+
|
|
|
+/* mapping of the OHCI CC status to error codes */
|
|
|
+static int cc_to_error[16] = {
|
|
|
+ /* No Error */ 0,
|
|
|
+ /* CRC Error */ USB_ST_CRC_ERR,
|
|
|
+ /* Bit Stuff */ USB_ST_BIT_ERR,
|
|
|
+ /* Data Togg */ USB_ST_CRC_ERR,
|
|
|
+ /* Stall */ USB_ST_STALLED,
|
|
|
+ /* DevNotResp */ -1,
|
|
|
+ /* PIDCheck */ USB_ST_BIT_ERR,
|
|
|
+ /* UnExpPID */ USB_ST_BIT_ERR,
|
|
|
+ /* DataOver */ USB_ST_BUF_ERR,
|
|
|
+ /* DataUnder */ USB_ST_BUF_ERR,
|
|
|
+ /* reservd */ -1,
|
|
|
+ /* reservd */ -1,
|
|
|
+ /* BufferOver */ USB_ST_BUF_ERR,
|
|
|
+ /* BuffUnder */ USB_ST_BUF_ERR,
|
|
|
+ /* Not Access */ -1,
|
|
|
+ /* Not Access */ -1
|
|
|
+};
|
|
|
+
|
|
|
+static const char *cc_to_string[16] = {
|
|
|
+ "No Error",
|
|
|
+ "CRC: Last data packet from endpoint contained a CRC error.",
|
|
|
+ "BITSTUFFING: Last data packet from endpoint contained a bit " \
|
|
|
+ "stuffing violation",
|
|
|
+ "DATATOGGLEMISMATCH: Last packet from endpoint had data toggle PID\n" \
|
|
|
+ "that did not match the expected value.",
|
|
|
+ "STALL: TD was moved to the Done Queue because the endpoint returned" \
|
|
|
+ " a STALL PID",
|
|
|
+ "DEVICENOTRESPONDING: Device did not respond to token (IN) or did\n" \
|
|
|
+ "not provide a handshake (OUT)",
|
|
|
+ "PIDCHECKFAILURE: Check bits on PID from endpoint failed on data PID\n"\
|
|
|
+ "(IN) or handshake (OUT)",
|
|
|
+ "UNEXPECTEDPID: Receive PID was not valid when encountered or PID\n" \
|
|
|
+ "value is not defined.",
|
|
|
+ "DATAOVERRUN: The amount of data returned by the endpoint exceeded\n" \
|
|
|
+ "either the size of the maximum data packet allowed\n" \
|
|
|
+ "from the endpoint (found in MaximumPacketSize field\n" \
|
|
|
+ "of ED) or the remaining buffer size.",
|
|
|
+ "DATAUNDERRUN: The endpoint returned less than MaximumPacketSize\n" \
|
|
|
+ "and that amount was not sufficient to fill the\n" \
|
|
|
+ "specified buffer",
|
|
|
+ "reserved1",
|
|
|
+ "reserved2",
|
|
|
+ "BUFFEROVERRUN: During an IN, HC received data from endpoint faster\n" \
|
|
|
+ "than it could be written to system memory",
|
|
|
+ "BUFFERUNDERRUN: During an OUT, HC could not retrieve data from\n" \
|
|
|
+ "system memory fast enough to keep up with data USB " \
|
|
|
+ "data rate.",
|
|
|
+ "NOT ACCESSED: This code is set by software before the TD is placed" \
|
|
|
+ "on a list to be processed by the HC.(1)",
|
|
|
+ "NOT ACCESSED: This code is set by software before the TD is placed" \
|
|
|
+ "on a list to be processed by the HC.(2)",
|
|
|
+};
|
|
|
|
|
|
static inline u32 roothub_a(struct ohci *hc)
|
|
|
{ return ohci_readl(&hc->regs->roothub.a); }
|
|
@@ -124,11 +199,42 @@ static inline u32 roothub_portstatus(struct ohci *hc, int i)
|
|
|
{ return ohci_readl(&hc->regs->roothub.portstatus[i]); }
|
|
|
|
|
|
/* forward declaration */
|
|
|
-static int hc_interrupt(void);
|
|
|
-static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
|
|
- void *buffer, int transfer_len,
|
|
|
+static int hc_interrupt(ohci_t *ohci);
|
|
|
+static void td_submit_job(ohci_t *ohci, struct usb_device *dev,
|
|
|
+ unsigned long pipe, void *buffer, int transfer_len,
|
|
|
struct devrequest *setup, urb_priv_t *urb,
|
|
|
int interval);
|
|
|
+static int ep_link(ohci_t * ohci, ed_t * ed);
|
|
|
+static int ep_unlink(ohci_t * ohci, ed_t * ed);
|
|
|
+static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev,
|
|
|
+ unsigned long pipe, int interval, int load);
|
|
|
+
|
|
|
+/*-------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+/* TDs ... */
|
|
|
+static struct td *td_alloc(ohci_dev_t *ohci_dev, struct usb_device *usb_dev)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ struct td *td;
|
|
|
+
|
|
|
+ td = NULL;
|
|
|
+ for (i = 0; i < NUM_TD; i++)
|
|
|
+ {
|
|
|
+ if (ohci_dev->tds[i].usb_dev == NULL)
|
|
|
+ {
|
|
|
+ td = &ohci_dev->tds[i];
|
|
|
+ td->usb_dev = usb_dev;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return td;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void ed_free(struct ed *ed)
|
|
|
+{
|
|
|
+ ed->usb_dev = NULL;
|
|
|
+}
|
|
|
|
|
|
/*-------------------------------------------------------------------------*
|
|
|
* URB support functions
|
|
@@ -158,18 +264,18 @@ static void urb_free_priv(urb_priv_t *urb)
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
-static int sohci_get_current_frame_number(struct usb_device *dev);
|
|
|
+static int sohci_get_current_frame_number(ohci_t *ohci);
|
|
|
|
|
|
/* debug| print the main components of an URB
|
|
|
* small: 0) header + data packets 1) just header */
|
|
|
|
|
|
-static void pkt_print(urb_priv_t *purb, struct usb_device *dev,
|
|
|
+static void pkt_print(ohci_t *ohci, urb_priv_t *purb, struct usb_device *dev,
|
|
|
unsigned long pipe, void *buffer, int transfer_len,
|
|
|
struct devrequest *setup, char *str, int small)
|
|
|
{
|
|
|
dbg("%s URB:[%4x] dev:%2lu,ep:%2lu-%c,type:%s,len:%d/%d stat:%#lx",
|
|
|
str,
|
|
|
- sohci_get_current_frame_number(dev),
|
|
|
+ sohci_get_current_frame_number(ohci),
|
|
|
usb_pipedevice(pipe),
|
|
|
usb_pipeendpoint(pipe),
|
|
|
usb_pipeout(pipe)? 'O': 'I',
|
|
@@ -213,9 +319,11 @@ void ep_print_int_eds(ohci_t *ohci, char *str)
|
|
|
ed_p = &(ohci->hcca->int_table [i]);
|
|
|
if (*ed_p == 0)
|
|
|
continue;
|
|
|
+ invalidate_dcache_ed(ed_p);
|
|
|
printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i);
|
|
|
while (*ed_p != 0 && j--) {
|
|
|
ed_t *ed = (ed_t *)m32_swap(ed_p);
|
|
|
+ invalidate_dcache_ed(ed);
|
|
|
printf(" ed: %4x;", ed->hwINFO);
|
|
|
ed_p = &ed->hwNextED;
|
|
|
}
|
|
@@ -246,6 +354,7 @@ static void maybe_print_eds(char *label, __u32 value)
|
|
|
|
|
|
if (value) {
|
|
|
dbg("%s %08x", label, value);
|
|
|
+ invalidate_dcache_ed(edp);
|
|
|
dbg("%08x", edp->hwINFO);
|
|
|
dbg("%08x", edp->hwTailP);
|
|
|
dbg("%08x", edp->hwHeadP);
|
|
@@ -380,6 +489,7 @@ static void ohci_dump(ohci_t *controller, int verbose)
|
|
|
ohci_dump_status(controller);
|
|
|
if (verbose)
|
|
|
ep_print_int_eds(controller, "hcca");
|
|
|
+ invalidate_dcache_hcca(controller->hcca);
|
|
|
dbg("hcca frame #%04x", controller->hcca->frame_no);
|
|
|
ohci_dump_roothub(controller, 1);
|
|
|
}
|
|
@@ -391,9 +501,9 @@ static void ohci_dump(ohci_t *controller, int verbose)
|
|
|
|
|
|
/* get a transfer request */
|
|
|
|
|
|
-int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
|
|
|
+int sohci_submit_job(ohci_t *ohci, ohci_dev_t *ohci_dev, urb_priv_t *urb,
|
|
|
+ struct devrequest *setup)
|
|
|
{
|
|
|
- ohci_t *ohci;
|
|
|
ed_t *ed;
|
|
|
urb_priv_t *purb_priv = urb;
|
|
|
int i, size = 0;
|
|
@@ -403,8 +513,6 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
|
|
|
int transfer_len = urb->transfer_buffer_length;
|
|
|
int interval = urb->interval;
|
|
|
|
|
|
- ohci = &gohci;
|
|
|
-
|
|
|
/* when controller's hung, permit only roothub cleanup attempts
|
|
|
* such as powering down ports */
|
|
|
if (ohci->disabled) {
|
|
@@ -417,7 +525,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
|
|
|
urb->finished = 0;
|
|
|
|
|
|
/* every endpoint has a ed, locate and fill it */
|
|
|
- ed = ep_add_ed(dev, pipe, interval, 1);
|
|
|
+ ed = ep_add_ed(ohci_dev, dev, pipe, interval, 1);
|
|
|
if (!ed) {
|
|
|
err("sohci_submit_job: ENOMEM");
|
|
|
return -1;
|
|
@@ -453,7 +561,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
|
|
|
/* allocate the TDs */
|
|
|
/* note that td[0] was allocated in ep_add_ed */
|
|
|
for (i = 0; i < size; i++) {
|
|
|
- purb_priv->td[i] = td_alloc(dev);
|
|
|
+ purb_priv->td[i] = td_alloc(ohci_dev, dev);
|
|
|
if (!purb_priv->td[i]) {
|
|
|
purb_priv->length = i;
|
|
|
urb_free_priv(purb_priv);
|
|
@@ -473,7 +581,7 @@ int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup)
|
|
|
ep_link(ohci, ed);
|
|
|
|
|
|
/* fill the TDs and link it to the ed */
|
|
|
- td_submit_job(dev, pipe, buffer, transfer_len,
|
|
|
+ td_submit_job(ohci, dev, pipe, buffer, transfer_len,
|
|
|
setup, purb_priv, interval);
|
|
|
|
|
|
return 0;
|
|
@@ -495,7 +603,7 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
|
|
|
ohci_readl(®s->intrdisable); /* PCI posting flush */
|
|
|
}
|
|
|
urb->actual_length = 0;
|
|
|
- td_submit_job(
|
|
|
+ td_submit_job( hc,
|
|
|
urb->dev,
|
|
|
urb->pipe,
|
|
|
urb->transfer_buffer,
|
|
@@ -517,11 +625,9 @@ static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb)
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
/* tell us the current USB frame number */
|
|
|
-
|
|
|
-static int sohci_get_current_frame_number(struct usb_device *usb_dev)
|
|
|
+static int sohci_get_current_frame_number(ohci_t *ohci)
|
|
|
{
|
|
|
- ohci_t *ohci = &gohci;
|
|
|
-
|
|
|
+ invalidate_dcache_hcca(ohci->hcca);
|
|
|
return m16_swap(ohci->hcca->frame_no);
|
|
|
}
|
|
|
#endif
|
|
@@ -600,6 +706,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
|
|
|
switch (ed->type) {
|
|
|
case PIPE_CONTROL:
|
|
|
ed->hwNextED = 0;
|
|
|
+ flush_dcache_ed(ed);
|
|
|
if (ohci->ed_controltail == NULL)
|
|
|
ohci_writel(ed, &ohci->regs->ed_controlhead);
|
|
|
else
|
|
@@ -617,6 +724,7 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
|
|
|
|
|
|
case PIPE_BULK:
|
|
|
ed->hwNextED = 0;
|
|
|
+ flush_dcache_ed(ed);
|
|
|
if (ohci->ed_bulktail == NULL)
|
|
|
ohci_writel(ed, &ohci->regs->ed_bulkhead);
|
|
|
else
|
|
@@ -649,7 +757,9 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
|
|
|
inter = ep_rev(6,
|
|
|
((ed_t *)ed_p)->int_interval);
|
|
|
ed->hwNextED = *ed_p;
|
|
|
+ flush_dcache_ed(ed);
|
|
|
*ed_p = m32_swap((unsigned long)ed);
|
|
|
+ flush_dcache_hcca(ohci->hcca);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
@@ -662,6 +772,8 @@ static int ep_link(ohci_t *ohci, ed_t *edi)
|
|
|
static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
|
|
|
unsigned index, unsigned period)
|
|
|
{
|
|
|
+ __maybe_unused unsigned long aligned_ed_p;
|
|
|
+
|
|
|
for (; index < NUM_INTS; index += period) {
|
|
|
__u32 *ed_p = &ohci->hcca->int_table [index];
|
|
|
|
|
@@ -670,6 +782,12 @@ static void periodic_unlink(struct ohci *ohci, volatile struct ed *ed,
|
|
|
if (((struct ed *)
|
|
|
m32_swap((unsigned long)ed_p)) == ed) {
|
|
|
*ed_p = ed->hwNextED;
|
|
|
+#ifdef CONFIG_DM_USB
|
|
|
+ aligned_ed_p = (unsigned long)ed_p;
|
|
|
+ aligned_ed_p &= ~(ARCH_DMA_MINALIGN - 1);
|
|
|
+ flush_dcache_range(aligned_ed_p,
|
|
|
+ aligned_ed_p + ARCH_DMA_MINALIGN);
|
|
|
+#endif
|
|
|
break;
|
|
|
}
|
|
|
ed_p = &(((struct ed *)
|
|
@@ -689,6 +807,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
|
|
|
int i;
|
|
|
|
|
|
ed->hwINFO |= m32_swap(OHCI_ED_SKIP);
|
|
|
+ flush_dcache_ed(ed);
|
|
|
|
|
|
switch (ed->type) {
|
|
|
case PIPE_CONTROL:
|
|
@@ -702,6 +821,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
|
|
|
&ohci->regs->ed_controlhead);
|
|
|
} else {
|
|
|
ed->ed_prev->hwNextED = ed->hwNextED;
|
|
|
+ flush_dcache_ed(ed->ed_prev);
|
|
|
}
|
|
|
if (ohci->ed_controltail == ed) {
|
|
|
ohci->ed_controltail = ed->ed_prev;
|
|
@@ -722,6 +842,7 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
|
|
|
&ohci->regs->ed_bulkhead);
|
|
|
} else {
|
|
|
ed->ed_prev->hwNextED = ed->hwNextED;
|
|
|
+ flush_dcache_ed(ed->ed_prev);
|
|
|
}
|
|
|
if (ohci->ed_bulktail == ed) {
|
|
|
ohci->ed_bulktail = ed->ed_prev;
|
|
@@ -751,14 +872,14 @@ static int ep_unlink(ohci_t *ohci, ed_t *edi)
|
|
|
* info fields are setted anyway even though most of them should not
|
|
|
* change
|
|
|
*/
|
|
|
-static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
|
|
|
- int interval, int load)
|
|
|
+static ed_t *ep_add_ed(ohci_dev_t *ohci_dev, struct usb_device *usb_dev,
|
|
|
+ unsigned long pipe, int interval, int load)
|
|
|
{
|
|
|
td_t *td;
|
|
|
ed_t *ed_ret;
|
|
|
volatile ed_t *ed;
|
|
|
|
|
|
- ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint(pipe) << 1) |
|
|
|
+ ed = ed_ret = &ohci_dev->ed[(usb_pipeendpoint(pipe) << 1) |
|
|
|
(usb_pipecontrol(pipe)? 0: usb_pipeout(pipe))];
|
|
|
|
|
|
if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
|
|
@@ -769,12 +890,12 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
|
|
|
|
|
|
if (ed->state == ED_NEW) {
|
|
|
/* dummy td; end of td list for ed */
|
|
|
- td = td_alloc(usb_dev);
|
|
|
+ td = td_alloc(ohci_dev, usb_dev);
|
|
|
ed->hwTailP = m32_swap((unsigned long)td);
|
|
|
ed->hwHeadP = ed->hwTailP;
|
|
|
ed->state = ED_UNLINK;
|
|
|
ed->type = usb_pipetype(pipe);
|
|
|
- ohci_dev.ed_cnt++;
|
|
|
+ ohci_dev->ed_cnt++;
|
|
|
}
|
|
|
|
|
|
ed->hwINFO = m32_swap(usb_pipedevice(pipe)
|
|
@@ -790,6 +911,8 @@ static ed_t *ep_add_ed(struct usb_device *usb_dev, unsigned long pipe,
|
|
|
ed->int_load = load;
|
|
|
}
|
|
|
|
|
|
+ flush_dcache_ed(ed);
|
|
|
+
|
|
|
return ed_ret;
|
|
|
}
|
|
|
|
|
@@ -815,6 +938,7 @@ static void td_fill(ohci_t *ohci, unsigned int info,
|
|
|
/* use this td as the next dummy */
|
|
|
td_pt = urb_priv->td [index];
|
|
|
td_pt->hwNextTD = 0;
|
|
|
+ flush_dcache_td(td_pt);
|
|
|
|
|
|
/* fill the old dummy TD */
|
|
|
td = urb_priv->td [index] =
|
|
@@ -842,27 +966,30 @@ static void td_fill(ohci_t *ohci, unsigned int info,
|
|
|
td->hwBE = 0;
|
|
|
|
|
|
td->hwNextTD = m32_swap((unsigned long)td_pt);
|
|
|
+ flush_dcache_td(td);
|
|
|
|
|
|
/* append to queue */
|
|
|
td->ed->hwTailP = td->hwNextTD;
|
|
|
+ flush_dcache_ed(td->ed);
|
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
/* prepare all TDs of a transfer */
|
|
|
|
|
|
-static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
|
|
- void *buffer, int transfer_len,
|
|
|
+static void td_submit_job(ohci_t *ohci, struct usb_device *dev,
|
|
|
+ unsigned long pipe, void *buffer, int transfer_len,
|
|
|
struct devrequest *setup, urb_priv_t *urb,
|
|
|
int interval)
|
|
|
{
|
|
|
- ohci_t *ohci = &gohci;
|
|
|
int data_len = transfer_len;
|
|
|
void *data;
|
|
|
int cnt = 0;
|
|
|
__u32 info = 0;
|
|
|
unsigned int toggle = 0;
|
|
|
|
|
|
+ flush_dcache_buffer(buffer, data_len);
|
|
|
+
|
|
|
/* OHCI handles the DATA-toggles itself, we just use the USB-toggle
|
|
|
* bits for reseting */
|
|
|
if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
|
|
@@ -902,6 +1029,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
|
|
case PIPE_CONTROL:
|
|
|
/* Setup phase */
|
|
|
info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
|
|
|
+ flush_dcache_buffer(setup, 8);
|
|
|
td_fill(ohci, info, setup, 8, dev, cnt++, urb);
|
|
|
|
|
|
/* Optional Data phase */
|
|
@@ -914,7 +1042,7 @@ static void td_submit_job(struct usb_device *dev, unsigned long pipe,
|
|
|
}
|
|
|
|
|
|
/* Status phase */
|
|
|
- info = usb_pipeout(pipe)?
|
|
|
+ info = (usb_pipeout(pipe) || data_len == 0) ?
|
|
|
TD_CC | TD_DP_IN | TD_T_DATA1:
|
|
|
TD_CC | TD_DP_OUT | TD_T_DATA1;
|
|
|
td_fill(ohci, info, data, 0, dev, cnt++, urb);
|
|
@@ -973,6 +1101,7 @@ static void check_status(td_t *td_list)
|
|
|
if (cc) {
|
|
|
err(" USB-error: %s (%x)", cc_to_string[cc], cc);
|
|
|
|
|
|
+ invalidate_dcache_ed(td_list->ed);
|
|
|
if (*phwHeadP & m32_swap(0x1)) {
|
|
|
if (lurb_priv &&
|
|
|
((td_list->index + 1) < urb_len)) {
|
|
@@ -985,9 +1114,11 @@ static void check_status(td_t *td_list)
|
|
|
td_list->index - 1;
|
|
|
} else
|
|
|
*phwHeadP &= m32_swap(0xfffffff2);
|
|
|
+ flush_dcache_ed(td_list->ed);
|
|
|
}
|
|
|
#ifdef CONFIG_MPC5200
|
|
|
td_list->hwNextTD = 0;
|
|
|
+ flush_dcache_td(td_list);
|
|
|
#endif
|
|
|
}
|
|
|
}
|
|
@@ -1000,11 +1131,14 @@ static td_t *dl_reverse_done_list(ohci_t *ohci)
|
|
|
td_t *td_rev = NULL;
|
|
|
td_t *td_list = NULL;
|
|
|
|
|
|
+ invalidate_dcache_hcca(ohci->hcca);
|
|
|
td_list_hc = m32_swap(ohci->hcca->done_head) & 0xfffffff0;
|
|
|
ohci->hcca->done_head = 0;
|
|
|
+ flush_dcache_hcca(ohci->hcca);
|
|
|
|
|
|
while (td_list_hc) {
|
|
|
td_list = (td_t *)td_list_hc;
|
|
|
+ invalidate_dcache_td(td_list);
|
|
|
check_status(td_list);
|
|
|
td_list->next_dl_td = td_rev;
|
|
|
td_rev = td_list;
|
|
@@ -1039,6 +1173,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list)
|
|
|
urb_priv_t *lurb_priv;
|
|
|
__u32 tdINFO, edHeadP, edTailP;
|
|
|
|
|
|
+ invalidate_dcache_td(td_list);
|
|
|
tdINFO = m32_swap(td_list->hwINFO);
|
|
|
|
|
|
ed = td_list->ed;
|
|
@@ -1064,6 +1199,7 @@ static int takeback_td(ohci_t *ohci, td_t *td_list)
|
|
|
lurb_priv->td_cnt, lurb_priv->length);
|
|
|
|
|
|
if (ed->state != ED_NEW && (!usb_pipeint(lurb_priv->pipe))) {
|
|
|
+ invalidate_dcache_ed(ed);
|
|
|
edHeadP = m32_swap(ed->hwHeadP) & 0xfffffff0;
|
|
|
edTailP = m32_swap(ed->hwTailP);
|
|
|
|
|
@@ -1100,16 +1236,16 @@ static int dl_done_list(ohci_t *ohci)
|
|
|
#define OK(x) len = (x); break
|
|
|
#ifdef DEBUG
|
|
|
#define WR_RH_STAT(x) {info("WR:status %#8x", (x)); ohci_writel((x), \
|
|
|
- &gohci.regs->roothub.status); }
|
|
|
+ &ohci->regs->roothub.status); }
|
|
|
#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, \
|
|
|
- (x)); ohci_writel((x), &gohci.regs->roothub.portstatus[wIndex-1]); }
|
|
|
+ (x)); ohci_writel((x), &ohci->regs->roothub.portstatus[wIndex-1]); }
|
|
|
#else
|
|
|
-#define WR_RH_STAT(x) ohci_writel((x), &gohci.regs->roothub.status)
|
|
|
+#define WR_RH_STAT(x) ohci_writel((x), &ohci->regs->roothub.status)
|
|
|
#define WR_RH_PORTSTAT(x) ohci_writel((x), \
|
|
|
- &gohci.regs->roothub.portstatus[wIndex-1])
|
|
|
+ &ohci->regs->roothub.portstatus[wIndex-1])
|
|
|
#endif
|
|
|
-#define RD_RH_STAT roothub_status(&gohci)
|
|
|
-#define RD_RH_PORTSTAT roothub_portstatus(&gohci, wIndex-1)
|
|
|
+#define RD_RH_STAT roothub_status(ohci)
|
|
|
+#define RD_RH_PORTSTAT roothub_portstatus(ohci, wIndex-1)
|
|
|
|
|
|
/* request to virtual root hub */
|
|
|
|
|
@@ -1137,8 +1273,9 @@ int rh_check_port_status(ohci_t *controller)
|
|
|
return res;
|
|
|
}
|
|
|
|
|
|
-static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
|
|
- void *buffer, int transfer_len, struct devrequest *cmd)
|
|
|
+static int ohci_submit_rh_msg(ohci_t *ohci, struct usb_device *dev,
|
|
|
+ unsigned long pipe, void *buffer, int transfer_len,
|
|
|
+ struct devrequest *cmd)
|
|
|
{
|
|
|
void *data = buffer;
|
|
|
int leni = transfer_len;
|
|
@@ -1151,7 +1288,7 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
|
|
|
ALLOC_ALIGN_BUFFER(__u8, databuf, 16, sizeof(u32));
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
-pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|
|
+pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len,
|
|
|
cmd, "SUB(rh)", usb_pipein(pipe));
|
|
|
#else
|
|
|
mdelay(1);
|
|
@@ -1245,7 +1382,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|
|
break;
|
|
|
|
|
|
case RH_SET_ADDRESS:
|
|
|
- gohci.rh.devnum = wValue;
|
|
|
+ ohci->rh.devnum = wValue;
|
|
|
OK(0);
|
|
|
|
|
|
case RH_GET_DESCRIPTOR:
|
|
@@ -1290,7 +1427,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|
|
|
|
|
case RH_GET_DESCRIPTOR | RH_CLASS:
|
|
|
{
|
|
|
- __u32 temp = roothub_a(&gohci);
|
|
|
+ __u32 temp = roothub_a(ohci);
|
|
|
|
|
|
databuf[0] = 9; /* min length; */
|
|
|
databuf[1] = 0x29;
|
|
@@ -1309,7 +1446,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|
|
databuf[4] = 0;
|
|
|
databuf[5] = (temp & RH_A_POTPGT) >> 24;
|
|
|
databuf[6] = 0;
|
|
|
- temp = roothub_b(&gohci);
|
|
|
+ temp = roothub_b(ohci);
|
|
|
databuf[7] = temp & RH_B_DR;
|
|
|
if (databuf[2] < 7) {
|
|
|
databuf[8] = 0xff;
|
|
@@ -1338,7 +1475,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
- ohci_dump_roothub(&gohci, 1);
|
|
|
+ ohci_dump_roothub(ohci, 1);
|
|
|
#else
|
|
|
mdelay(1);
|
|
|
#endif
|
|
@@ -1350,7 +1487,7 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|
|
dev->status = stat;
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
- pkt_print(NULL, dev, pipe, buffer,
|
|
|
+ pkt_print(ohci, NULL, dev, pipe, buffer,
|
|
|
transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
|
|
|
#else
|
|
|
mdelay(1);
|
|
@@ -1363,8 +1500,9 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|
|
|
|
|
/* common code for handling submit messages - used for all but root hub */
|
|
|
/* accesses. */
|
|
|
-int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
- int transfer_len, struct devrequest *setup, int interval)
|
|
|
+static int submit_common_msg(ohci_t *ohci, struct usb_device *dev,
|
|
|
+ unsigned long pipe, void *buffer, int transfer_len,
|
|
|
+ struct devrequest *setup, int interval)
|
|
|
{
|
|
|
int stat = 0;
|
|
|
int maxsize = usb_maxpacket(dev, pipe);
|
|
@@ -1380,15 +1518,9 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
urb->transfer_buffer_length = transfer_len;
|
|
|
urb->interval = interval;
|
|
|
|
|
|
- /* device pulled? Shortcut the action. */
|
|
|
- if (devgone == dev) {
|
|
|
- dev->status = USB_ST_CRC_ERR;
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
#ifdef DEBUG
|
|
|
urb->actual_length = 0;
|
|
|
- pkt_print(urb, dev, pipe, buffer, transfer_len,
|
|
|
+ pkt_print(ohci, urb, dev, pipe, buffer, transfer_len,
|
|
|
setup, "SUB", usb_pipein(pipe));
|
|
|
#else
|
|
|
mdelay(1);
|
|
@@ -1399,14 +1531,14 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- if (sohci_submit_job(urb, setup) < 0) {
|
|
|
+ if (sohci_submit_job(ohci, &ohci->ohci_dev, urb, setup) < 0) {
|
|
|
err("sohci_submit_job failed");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
mdelay(10);
|
|
|
- /* ohci_dump_status(&gohci); */
|
|
|
+ /* ohci_dump_status(ohci); */
|
|
|
#endif
|
|
|
|
|
|
timeout = USB_TIMEOUT_MS(pipe);
|
|
@@ -1414,7 +1546,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
/* wait for it to complete */
|
|
|
for (;;) {
|
|
|
/* check whether the controller is done */
|
|
|
- stat = hc_interrupt();
|
|
|
+ stat = hc_interrupt(ohci);
|
|
|
if (stat < 0) {
|
|
|
stat = USB_ST_CRC_ERR;
|
|
|
break;
|
|
@@ -1440,7 +1572,8 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
dbg("*");
|
|
|
|
|
|
} else {
|
|
|
- err("CTL:TIMEOUT ");
|
|
|
+ if (!usb_pipeint(pipe))
|
|
|
+ err("CTL:TIMEOUT ");
|
|
|
dbg("submit_common_msg: TO status %x\n", stat);
|
|
|
urb->finished = 1;
|
|
|
stat = USB_ST_CRC_ERR;
|
|
@@ -1451,8 +1584,11 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
dev->status = stat;
|
|
|
dev->act_len = urb->actual_length;
|
|
|
|
|
|
+ if (usb_pipein(pipe) && dev->status == 0 && dev->act_len)
|
|
|
+ invalidate_dcache_buffer(buffer, dev->act_len);
|
|
|
+
|
|
|
#ifdef DEBUG
|
|
|
- pkt_print(urb, dev, pipe, buffer, transfer_len,
|
|
|
+ pkt_print(ohci, urb, dev, pipe, buffer, transfer_len,
|
|
|
setup, "RET(ctlr)", usb_pipein(pipe));
|
|
|
#else
|
|
|
mdelay(1);
|
|
@@ -1469,17 +1605,27 @@ int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
int transfer_len)
|
|
|
{
|
|
|
info("submit_bulk_msg");
|
|
|
- return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
|
|
|
+ return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len,
|
|
|
+ NULL, 0);
|
|
|
}
|
|
|
|
|
|
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
- int transfer_len, struct devrequest *setup)
|
|
|
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
+ int transfer_len, int interval)
|
|
|
+{
|
|
|
+ info("submit_int_msg");
|
|
|
+ return submit_common_msg(&gohci, dev, pipe, buffer, transfer_len, NULL,
|
|
|
+ interval);
|
|
|
+}
|
|
|
+
|
|
|
+static int _ohci_submit_control_msg(ohci_t *ohci, struct usb_device *dev,
|
|
|
+ unsigned long pipe, void *buffer, int transfer_len,
|
|
|
+ struct devrequest *setup)
|
|
|
{
|
|
|
int maxsize = usb_maxpacket(dev, pipe);
|
|
|
|
|
|
info("submit_control_msg");
|
|
|
#ifdef DEBUG
|
|
|
- pkt_print(NULL, dev, pipe, buffer, transfer_len,
|
|
|
+ pkt_print(ohci, NULL, dev, pipe, buffer, transfer_len,
|
|
|
setup, "SUB", usb_pipein(pipe));
|
|
|
#else
|
|
|
mdelay(1);
|
|
@@ -1489,22 +1635,15 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
pipe);
|
|
|
return -1;
|
|
|
}
|
|
|
- if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
|
|
|
- gohci.rh.dev = dev;
|
|
|
+ if (((pipe >> 8) & 0x7f) == ohci->rh.devnum) {
|
|
|
+ ohci->rh.dev = dev;
|
|
|
/* root hub - redirect */
|
|
|
- return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
|
|
|
- setup);
|
|
|
+ return ohci_submit_rh_msg(ohci, dev, pipe, buffer,
|
|
|
+ transfer_len, setup);
|
|
|
}
|
|
|
|
|
|
- return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
|
|
|
-}
|
|
|
-
|
|
|
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
|
|
|
- int transfer_len, int interval)
|
|
|
-{
|
|
|
- info("submit_int_msg");
|
|
|
- return submit_common_msg(dev, pipe, buffer, transfer_len, NULL,
|
|
|
- interval);
|
|
|
+ return submit_common_msg(ohci, dev, pipe, buffer, transfer_len,
|
|
|
+ setup, 0);
|
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------*
|
|
@@ -1648,13 +1787,14 @@ static int hc_start(ohci_t *ohci)
|
|
|
|
|
|
/* an interrupt happens */
|
|
|
|
|
|
-static int hc_interrupt(void)
|
|
|
+static int hc_interrupt(ohci_t *ohci)
|
|
|
{
|
|
|
- ohci_t *ohci = &gohci;
|
|
|
struct ohci_regs *regs = ohci->regs;
|
|
|
int ints;
|
|
|
int stat = -1;
|
|
|
|
|
|
+ invalidate_dcache_hcca(ohci->hcca);
|
|
|
+
|
|
|
if ((ohci->hcca->done_head != 0) &&
|
|
|
!(m32_swap(ohci->hcca->done_head) & 0x01)) {
|
|
|
ints = OHCI_INTR_WDH;
|
|
@@ -1702,7 +1842,7 @@ static int hc_interrupt(void)
|
|
|
mdelay(1);
|
|
|
ohci_writel(OHCI_INTR_WDH, ®s->intrdisable);
|
|
|
(void)ohci_readl(®s->intrdisable); /* flush */
|
|
|
- stat = dl_done_list(&gohci);
|
|
|
+ stat = dl_done_list(ohci);
|
|
|
ohci_writel(OHCI_INTR_WDH, ®s->intrenable);
|
|
|
(void)ohci_readl(®s->intrdisable); /* flush */
|
|
|
}
|
|
@@ -1772,21 +1912,9 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
|
|
|
err("HCCA not aligned!!");
|
|
|
return -1;
|
|
|
}
|
|
|
- phcca = &ghcca[0];
|
|
|
- info("aligned ghcca %p", phcca);
|
|
|
- memset(&ohci_dev, 0, sizeof(struct ohci_device));
|
|
|
- if ((__u32)&ohci_dev.ed[0] & 0x7) {
|
|
|
- err("EDs not aligned!!");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
|
|
|
- if ((__u32)gtd & 0x7) {
|
|
|
- err("TDs not aligned!!");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- ptd = gtd;
|
|
|
- gohci.hcca = phcca;
|
|
|
- memset(phcca, 0, sizeof(struct ohci_hcca));
|
|
|
+ gohci.hcca = &ghcca[0];
|
|
|
+ info("aligned ghcca %p", gohci.hcca);
|
|
|
+ memset(gohci.hcca, 0, sizeof(struct ohci_hcca));
|
|
|
|
|
|
gohci.disabled = 1;
|
|
|
gohci.sleeping = 0;
|
|
@@ -1880,3 +2008,10 @@ int usb_lowlevel_stop(int index)
|
|
|
ohci_inited = 0;
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+int submit_control_msg(struct usb_device *dev, unsigned long pipe,
|
|
|
+ void *buffer, int transfer_len, struct devrequest *setup)
|
|
|
+{
|
|
|
+ return _ohci_submit_control_msg(&gohci, dev, pipe, buffer,
|
|
|
+ transfer_len, setup);
|
|
|
+}
|