summaryrefslogtreecommitdiffstats
path: root/drivers/staging/octeon-usb/octeon-hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/octeon-usb/octeon-hcd.c')
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c130
1 files changed, 90 insertions, 40 deletions
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index 8b8ce7293c52..c4c731f60529 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -47,6 +47,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/prefetch.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
@@ -245,9 +246,6 @@ enum cvmx_usb_pipe_flags {
__CVMX_USB_PIPE_FLAGS_NEED_PING = 1 << 18,
};
-/* Normal prefetch that use the pref instruction. */
-#define CVMX_PREFETCH(address, offset) asm volatile ("pref %[type], %[off](%[rbase])" : : [rbase] "d" (address), [off] "I" (offset), [type] "n" (0))
-
/* Maximum number of times to retry failed transactions */
#define MAX_RETRIES 3
@@ -462,7 +460,8 @@ struct octeon_hcd {
} while (0)
/* Returns the IO address to push/pop stuff data from the FIFOs */
-#define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000)
+#define USB_FIFO_ADDRESS(channel, usb_index) \
+ (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000)
/**
* struct octeon_temp_buffer - a bounce buffer for USB transfers
@@ -892,6 +891,7 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
*/
{
union cvmx_usbcx_gusbcfg usbcx_gusbcfg;
+
usbcx_gusbcfg.u32 = __cvmx_usb_read_csr32(usb,
CVMX_USBCX_GUSBCFG(usb->index));
usbcx_gusbcfg.s.toutcal = 0;
@@ -949,6 +949,7 @@ static int cvmx_usb_initialize(struct cvmx_usb_state *usb,
*/
{
union cvmx_usbcx_hcfg usbcx_hcfg;
+
usbcx_hcfg.u32 = __cvmx_usb_read_csr32(usb,
CVMX_USBCX_HCFG(usb->index));
usbcx_hcfg.s.fslssupp = 0;
@@ -1076,6 +1077,7 @@ static int cvmx_usb_enable(struct cvmx_usb_state *usb)
*/
{
union cvmx_usbcx_gnptxfsiz siz;
+
siz.u32 = __cvmx_usb_read_csr32(usb,
CVMX_USBCX_GNPTXFSIZ(usb->index));
siz.s.nptxfdep = usbcx_ghwcfg3.s.dfifodepth / 2;
@@ -1090,6 +1092,7 @@ static int cvmx_usb_enable(struct cvmx_usb_state *usb)
*/
{
union cvmx_usbcx_hptxfsiz siz;
+
siz.u32 = __cvmx_usb_read_csr32(usb,
CVMX_USBCX_HPTXFSIZ(usb->index));
siz.s.ptxfsize = usbcx_ghwcfg3.s.dfifodepth / 4;
@@ -1219,8 +1222,8 @@ static struct cvmx_usb_port_status cvmx_usb_get_status(
* Returns: A non-NULL value is a pipe. NULL means an error.
*/
static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
- int device_addr, int
- endpoint_num,
+ int device_addr,
+ int endpoint_num,
enum cvmx_usb_speed
device_speed,
int max_packet,
@@ -1286,7 +1289,8 @@ static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
if (__cvmx_usb_pipe_needs_split(usb, pipe)) {
pipe->interval = interval*8;
/* Force start splits to be schedule on uFrame 0 */
- pipe->next_tx_frame = ((usb->frame_number+7)&~7) + pipe->interval;
+ pipe->next_tx_frame = ((usb->frame_number+7)&~7) +
+ pipe->interval;
} else {
pipe->interval = interval;
pipe->next_tx_frame = usb->frame_number + pipe->interval;
@@ -1337,9 +1341,13 @@ static void __cvmx_usb_poll_rx_fifo(struct cvmx_usb_state *usb)
return;
/* Get where the DMA engine would have written this data */
- address = __cvmx_usb_read_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8);
+ address = __cvmx_usb_read_csr64(usb,
+ CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8);
+
ptr = cvmx_phys_to_ptr(address);
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, address + bytes);
+ __cvmx_usb_write_csr64(usb,
+ CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8,
+ address + bytes);
/* Loop writing the FIFO data for this packet into memory */
while (bytes > 0) {
@@ -1423,6 +1431,7 @@ static void __cvmx_usb_poll_tx_fifo(struct cvmx_usb_state *usb)
{
if (usb->periodic.head != usb->periodic.tail) {
union cvmx_usbcx_hptxsts tx_status;
+
tx_status.u32 = __cvmx_usb_read_csr32(usb,
CVMX_USBCX_HPTXSTS(usb->index));
if (__cvmx_usb_fill_tx_hw(usb, &usb->periodic,
@@ -1438,6 +1447,7 @@ static void __cvmx_usb_poll_tx_fifo(struct cvmx_usb_state *usb)
if (usb->nonperiodic.head != usb->nonperiodic.tail) {
union cvmx_usbcx_gnptxsts tx_status;
+
tx_status.u32 = __cvmx_usb_read_csr32(usb,
CVMX_USBCX_GNPTXSTS(usb->index));
if (__cvmx_usb_fill_tx_hw(usb, &usb->nonperiodic,
@@ -1536,25 +1546,33 @@ static void __cvmx_usb_start_channel_control(struct cvmx_usb_state *usb,
switch (transaction->stage) {
case CVMX_USB_STAGE_NON_CONTROL:
case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
- cvmx_dprintf("%s: ERROR - Non control stage\n", __FUNCTION__);
+ cvmx_dprintf("%s: ERROR - Non control stage\n", __func__);
break;
case CVMX_USB_STAGE_SETUP:
usbc_hctsiz.s.pid = 3; /* Setup */
bytes_to_transfer = sizeof(*header);
/* All Control operations start with a setup going OUT */
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, CVMX_USB_DIRECTION_OUT);
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+ union cvmx_usbcx_hccharx, epdir,
+ CVMX_USB_DIRECTION_OUT);
/*
* Setup send the control header instead of the buffer data. The
* buffer data will be used in the next stage
*/
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, transaction->control_header);
+ __cvmx_usb_write_csr64(usb,
+ CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8,
+ transaction->control_header);
break;
case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
usbc_hctsiz.s.pid = 3; /* Setup */
bytes_to_transfer = 0;
/* All Control operations start with a setup going OUT */
- USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index), union cvmx_usbcx_hccharx, epdir, CVMX_USB_DIRECTION_OUT);
- USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index), union cvmx_usbcx_hcspltx, compsplt, 1);
+ USB_SET_FIELD32(CVMX_USBCX_HCCHARX(channel, usb->index),
+ union cvmx_usbcx_hccharx, epdir,
+ CVMX_USB_DIRECTION_OUT);
+
+ USB_SET_FIELD32(CVMX_USBCX_HCSPLTX(channel, usb->index),
+ union cvmx_usbcx_hcspltx, compsplt, 1);
break;
case CVMX_USB_STAGE_DATA:
usbc_hctsiz.s.pid = __cvmx_usb_get_data_pid(pipe);
@@ -1684,6 +1702,7 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
/* Clear all channel status bits */
usbc_hcint.u32 = __cvmx_usb_read_csr32(usb,
CVMX_USBCX_HCINTX(channel, usb->index));
+
__cvmx_usb_write_csr32(usb,
CVMX_USBCX_HCINTX(channel, usb->index),
usbc_hcint.u32);
@@ -1714,18 +1733,31 @@ static void __cvmx_usb_start_channel(struct cvmx_usb_state *usb,
__cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), usbc_hcintmsk.u32);
/* Enable the channel interrupt to propagate */
- usbc_haintmsk.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index));
+ usbc_haintmsk.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HAINTMSK(usb->index));
usbc_haintmsk.s.haintmsk |= 1<<channel;
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index), usbc_haintmsk.u32);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HAINTMSK(usb->index),
+ usbc_haintmsk.u32);
}
/* Setup the locations the DMA engines use */
{
- uint64_t dma_address = transaction->buffer + transaction->actual_bytes;
+ uint64_t dma_address = transaction->buffer +
+ transaction->actual_bytes;
+
if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
- dma_address = transaction->buffer + transaction->iso_packets[0].offset + transaction->actual_bytes;
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8, dma_address);
- __cvmx_usb_write_csr64(usb, CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8, dma_address);
+ dma_address = transaction->buffer +
+ transaction->iso_packets[0].offset +
+ transaction->actual_bytes;
+
+ __cvmx_usb_write_csr64(usb,
+ CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) + channel*8,
+ dma_address);
+
+ __cvmx_usb_write_csr64(usb,
+ CVMX_USBNX_DMA0_INB_CHN0(usb->index) + channel*8,
+ dma_address);
}
/* Setup both the size of the transfer and the SPLIT characteristics */
@@ -2008,8 +2040,7 @@ static struct cvmx_usb_pipe *__cvmx_usb_find_ready_pipe(
((((int)current_frame - (int)pipe->split_sc_frame)
& 0x7f) < 0x40)) &&
(!usb->active_split || (usb->active_split == t))) {
- CVMX_PREFETCH(pipe, 128);
- CVMX_PREFETCH(t, 0);
+ prefetch(t);
return pipe;
}
}
@@ -2036,8 +2067,16 @@ static void __cvmx_usb_schedule(struct cvmx_usb_state *usb, int is_sof)
* Without DMA we need to be careful to not schedule something
* at the end of a frame and cause an overrun.
*/
- union cvmx_usbcx_hfnum hfnum = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index))};
- union cvmx_usbcx_hfir hfir = {.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFIR(usb->index))};
+ union cvmx_usbcx_hfnum hfnum = {
+ .u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HFNUM(usb->index))
+ };
+
+ union cvmx_usbcx_hfir hfir = {
+ .u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HFIR(usb->index))
+ };
+
if (hfnum.s.frrem < hfir.s.frint/4)
goto done;
}
@@ -2522,6 +2561,7 @@ static int cvmx_usb_cancel_all(struct cvmx_usb_state *usb,
/* Simply loop through and attempt to cancel each transaction */
list_for_each_entry_safe(transaction, next, &pipe->transactions, node) {
int result = cvmx_usb_cancel(usb, pipe, transaction);
+
if (unlikely(result != 0))
return result;
}
@@ -2654,19 +2694,20 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
}
/* Disable the channel interrupts now that it is done */
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_HCINTMSKX(channel, usb->index), 0);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_HCINTMSKX(channel, usb->index),
+ 0);
usb->idle_hardware_channels |= (1<<channel);
/* Make sure this channel is tied to a valid pipe */
pipe = usb->pipe_for_channel[channel];
- CVMX_PREFETCH(pipe, 0);
- CVMX_PREFETCH(pipe, 128);
+ prefetch(pipe);
if (!pipe)
return 0;
transaction = list_first_entry(&pipe->transactions,
typeof(*transaction),
node);
- CVMX_PREFETCH(transaction, 0);
+ prefetch(transaction);
/*
* Disconnect this pipe from the HW channel. Later the schedule
@@ -3021,7 +3062,8 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
*/
if (!buffer_space_left ||
(bytes_this_transfer < 188)) {
- pipe->next_tx_frame += pipe->interval;
+ pipe->next_tx_frame +=
+ pipe->interval;
__cvmx_usb_perform_complete(
usb,
pipe,
@@ -3083,6 +3125,7 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
pipe->interval;
} else {
struct cvmx_usb_port_status port;
+
port = cvmx_usb_get_status(usb);
if (port.port_enabled) {
/* We'll retry the exact same transaction again */
@@ -3123,24 +3166,24 @@ static int cvmx_usb_poll(struct cvmx_usb_state *usb)
union cvmx_usbcx_hfnum usbc_hfnum;
union cvmx_usbcx_gintsts usbc_gintsts;
- CVMX_PREFETCH(usb, 0);
- CVMX_PREFETCH(usb, 1*128);
- CVMX_PREFETCH(usb, 2*128);
- CVMX_PREFETCH(usb, 3*128);
- CVMX_PREFETCH(usb, 4*128);
+ prefetch_range(usb, sizeof(*usb));
/* Update the frame counter */
- usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
+ usbc_hfnum.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HFNUM(usb->index));
if ((usb->frame_number&0x3fff) > usbc_hfnum.s.frnum)
usb->frame_number += 0x4000;
usb->frame_number &= ~0x3fffull;
usb->frame_number |= usbc_hfnum.s.frnum;
/* Read the pending interrupts */
- usbc_gintsts.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_GINTSTS(usb->index));
+ usbc_gintsts.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_GINTSTS(usb->index));
/* Clear the interrupts now that we know about them */
- __cvmx_usb_write_csr32(usb, CVMX_USBCX_GINTSTS(usb->index), usbc_gintsts.u32);
+ __cvmx_usb_write_csr32(usb,
+ CVMX_USBCX_GINTSTS(usb->index),
+ usbc_gintsts.u32);
if (usbc_gintsts.s.rxflvl) {
/*
@@ -3196,7 +3239,9 @@ static int cvmx_usb_poll(struct cvmx_usb_state *usb)
* to clear this bit.
*/
union cvmx_usbcx_haint usbc_haint;
- usbc_haint.u32 = __cvmx_usb_read_csr32(usb, CVMX_USBCX_HAINT(usb->index));
+
+ usbc_haint.u32 = __cvmx_usb_read_csr32(usb,
+ CVMX_USBCX_HAINT(usb->index));
while (usbc_haint.u32) {
int channel;
@@ -3267,6 +3312,7 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
enum cvmx_usb_speed speed;
int split_device = 0;
int split_port = 0;
+
switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS:
transfer_type = CVMX_USB_TRANSFER_ISOCHRONOUS;
@@ -3303,6 +3349,7 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
* tree.
*/
struct usb_device *dev = urb->dev;
+
while (dev->parent) {
/*
* If our parent is high speed then he'll
@@ -3462,6 +3509,7 @@ static void octeon_usb_endpoint_disable(struct usb_hcd *hcd,
struct octeon_hcd *priv = hcd_to_octeon(hcd);
struct cvmx_usb_pipe *pipe = ep->hcpriv;
unsigned long flags;
+
spin_lock_irqsave(&priv->lock, flags);
cvmx_usb_cancel_all(&priv->usb, pipe);
if (cvmx_usb_close_pipe(&priv->usb, pipe))
@@ -3483,10 +3531,11 @@ static int octeon_usb_hub_status_data(struct usb_hcd *hcd, char *buf)
buf[0] = 0;
buf[0] = port_status.connect_change << 1;
- return (buf[0] != 0);
+ return buf[0] != 0;
}
-static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength)
+static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
{
struct octeon_hcd *priv = hcd_to_octeon(hcd);
struct device *dev = hcd->self.controller;
@@ -3778,6 +3827,7 @@ static int octeon_usb_probe(struct platform_device *pdev)
if (irq < 0) {
/* Defective device tree, but we know how to fix it. */
irq_hw_number_t hwirq = usb_num ? (1 << 6) + 17 : 56;
+
irq = irq_create_mapping(NULL, hwirq);
}