aboutsummaryrefslogtreecommitdiffstats
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.c1094
1 files changed, 527 insertions, 567 deletions
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index 6f2871784ba5..17442b3ed849 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -43,29 +43,15 @@
* CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR
* PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
*/
-#include <linux/kernel.h>
+
+#include <linux/usb.h>
+#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
+#include <linux/usb/hcd.h>
#include <linux/prefetch.h>
-#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/usb.h>
-
-#include <linux/time.h>
-#include <linux/delay.h>
-
-#include <asm/octeon/cvmx.h>
-#include <asm/octeon/cvmx-iob-defs.h>
-
-#include <linux/usb/hcd.h>
-
-#include <linux/err.h>
#include <asm/octeon/octeon.h>
-#include <asm/octeon/cvmx-helper.h>
-#include <asm/octeon/cvmx-sysinfo.h>
-#include <asm/octeon/cvmx-helper-board.h>
#include "octeon-hcd.h"
@@ -113,35 +99,35 @@ enum cvmx_usb_direction {
};
/**
- * enum cvmx_usb_complete - possible callback function status codes
+ * enum cvmx_usb_status - possible callback function status codes
*
- * @CVMX_USB_COMPLETE_SUCCESS: The transaction / operation finished without
+ * @CVMX_USB_STATUS_OK: The transaction / operation finished without
* any errors
- * @CVMX_USB_COMPLETE_SHORT: FIXME: This is currently not implemented
- * @CVMX_USB_COMPLETE_CANCEL: The transaction was canceled while in flight
+ * @CVMX_USB_STATUS_SHORT: FIXME: This is currently not implemented
+ * @CVMX_USB_STATUS_CANCEL: The transaction was canceled while in flight
* by a user call to cvmx_usb_cancel
- * @CVMX_USB_COMPLETE_ERROR: The transaction aborted with an unexpected
+ * @CVMX_USB_STATUS_ERROR: The transaction aborted with an unexpected
* error status
- * @CVMX_USB_COMPLETE_STALL: The transaction received a USB STALL response
+ * @CVMX_USB_STATUS_STALL: The transaction received a USB STALL response
* from the device
- * @CVMX_USB_COMPLETE_XACTERR: The transaction failed with an error from the
+ * @CVMX_USB_STATUS_XACTERR: The transaction failed with an error from the
* device even after a number of retries
- * @CVMX_USB_COMPLETE_DATATGLERR: The transaction failed with a data toggle
+ * @CVMX_USB_STATUS_DATATGLERR: The transaction failed with a data toggle
* error even after a number of retries
- * @CVMX_USB_COMPLETE_BABBLEERR: The transaction failed with a babble error
- * @CVMX_USB_COMPLETE_FRAMEERR: The transaction failed with a frame error
+ * @CVMX_USB_STATUS_BABBLEERR: The transaction failed with a babble error
+ * @CVMX_USB_STATUS_FRAMEERR: The transaction failed with a frame error
* even after a number of retries
*/
-enum cvmx_usb_complete {
- CVMX_USB_COMPLETE_SUCCESS,
- CVMX_USB_COMPLETE_SHORT,
- CVMX_USB_COMPLETE_CANCEL,
- CVMX_USB_COMPLETE_ERROR,
- CVMX_USB_COMPLETE_STALL,
- CVMX_USB_COMPLETE_XACTERR,
- CVMX_USB_COMPLETE_DATATGLERR,
- CVMX_USB_COMPLETE_BABBLEERR,
- CVMX_USB_COMPLETE_FRAMEERR,
+enum cvmx_usb_status {
+ CVMX_USB_STATUS_OK,
+ CVMX_USB_STATUS_SHORT,
+ CVMX_USB_STATUS_CANCEL,
+ CVMX_USB_STATUS_ERROR,
+ CVMX_USB_STATUS_STALL,
+ CVMX_USB_STATUS_XACTERR,
+ CVMX_USB_STATUS_DATATGLERR,
+ CVMX_USB_STATUS_BABBLEERR,
+ CVMX_USB_STATUS_FRAMEERR,
};
/**
@@ -160,13 +146,13 @@ enum cvmx_usb_complete {
* status call.
*/
struct cvmx_usb_port_status {
- uint32_t reserved : 25;
- uint32_t port_enabled : 1;
- uint32_t port_over_current : 1;
- uint32_t port_powered : 1;
+ u32 reserved : 25;
+ u32 port_enabled : 1;
+ u32 port_over_current : 1;
+ u32 port_powered : 1;
enum cvmx_usb_speed port_speed : 2;
- uint32_t connected : 1;
- uint32_t connect_change : 1;
+ u32 connected : 1;
+ u32 connect_change : 1;
};
/**
@@ -180,7 +166,7 @@ struct cvmx_usb_port_status {
struct cvmx_usb_iso_packet {
int offset;
int length;
- enum cvmx_usb_complete status;
+ enum cvmx_usb_status status;
};
/**
@@ -234,13 +220,13 @@ enum cvmx_usb_pipe_flags {
* The low level hardware can transfer a maximum of this number of bytes in each
* transfer. The field is 19 bits wide
*/
-#define MAX_TRANSFER_BYTES ((1<<19)-1)
+#define MAX_TRANSFER_BYTES ((1 << 19) - 1)
/*
* The low level hardware can transfer a maximum of this number of packets in
* each transfer. The field is 10 bits wide
*/
-#define MAX_TRANSFER_PACKETS ((1<<10)-1)
+#define MAX_TRANSFER_PACKETS ((1 << 10) - 1)
/**
* Logical transactions may take numerous low level
@@ -284,9 +270,9 @@ enum cvmx_usb_stage {
struct cvmx_usb_transaction {
struct list_head node;
enum cvmx_usb_transfer type;
- uint64_t buffer;
+ u64 buffer;
int buffer_length;
- uint64_t control_header;
+ u64 control_header;
int iso_start_frame;
int iso_number_packets;
struct cvmx_usb_iso_packet *iso_packets;
@@ -328,36 +314,37 @@ struct cvmx_usb_transaction {
struct cvmx_usb_pipe {
struct list_head node;
struct list_head transactions;
- uint64_t interval;
- uint64_t next_tx_frame;
+ u64 interval;
+ u64 next_tx_frame;
enum cvmx_usb_pipe_flags flags;
enum cvmx_usb_speed device_speed;
enum cvmx_usb_transfer transfer_type;
enum cvmx_usb_direction transfer_dir;
int multi_count;
- uint16_t max_packet;
- uint8_t device_addr;
- uint8_t endpoint_num;
- uint8_t hub_device_addr;
- uint8_t hub_port;
- uint8_t pid_toggle;
- uint8_t channel;
- int8_t split_sc_frame;
+ u16 max_packet;
+ u8 device_addr;
+ u8 endpoint_num;
+ u8 hub_device_addr;
+ u8 hub_port;
+ u8 pid_toggle;
+ u8 channel;
+ s8 split_sc_frame;
};
struct cvmx_usb_tx_fifo {
struct {
int channel;
int size;
- uint64_t address;
- } entry[MAX_CHANNELS+1];
+ u64 address;
+ } entry[MAX_CHANNELS + 1];
int head;
int tail;
};
/**
- * struct cvmx_usb_state - the state of the USB block
+ * struct octeon_hcd - the state of the USB block
*
+ * lock: Serialization lock.
* init_flags: Flags passed to initialize.
* index: Which USB block this is for.
* idle_hardware_channels: Bit set for every idle hardware channel.
@@ -372,7 +359,8 @@ struct cvmx_usb_tx_fifo {
* frame_number: Increments every SOF interrupt for time keeping.
* active_split: Points to the current active split, or NULL.
*/
-struct cvmx_usb_state {
+struct octeon_hcd {
+ spinlock_t lock; /* serialization lock */
int init_flags;
int index;
int idle_hardware_channels;
@@ -382,23 +370,18 @@ struct cvmx_usb_state {
struct cvmx_usb_port_status port_status;
struct list_head idle_pipes;
struct list_head active_pipes[4];
- uint64_t frame_number;
+ u64 frame_number;
struct cvmx_usb_transaction *active_split;
struct cvmx_usb_tx_fifo periodic;
struct cvmx_usb_tx_fifo nonperiodic;
};
-struct octeon_hcd {
- spinlock_t lock;
- struct cvmx_usb_state usb;
-};
-
/* This macro spins on a register waiting for it to reach a condition. */
#define CVMX_WAIT_FOR_FIELD32(address, _union, cond, timeout_usec) \
({int result; \
do { \
- uint64_t done = cvmx_get_cycle() + (uint64_t)timeout_usec * \
- octeon_get_clock_rate() / 1000000; \
+ u64 done = cvmx_get_cycle() + (u64)timeout_usec * \
+ octeon_get_clock_rate() / 1000000; \
union _union c; \
\
while (1) { \
@@ -431,7 +414,7 @@ struct octeon_hcd {
/* 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)
+ (CVMX_USBCX_GOTGCTL(usb_index) + ((channel) + 1) * 0x1000)
/**
* struct octeon_temp_buffer - a bounce buffer for USB transfers
@@ -447,11 +430,6 @@ struct octeon_temp_buffer {
u8 data[0];
};
-static inline struct octeon_hcd *cvmx_usb_to_octeon(struct cvmx_usb_state *p)
-{
- return container_of(p, struct octeon_hcd, usb);
-}
-
static inline struct usb_hcd *octeon_to_hcd(struct octeon_hcd *p)
{
return container_of((void *)p, struct usb_hcd, hcd_priv);
@@ -562,14 +540,12 @@ static void octeon_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
*
* Returns: Result of the read
*/
-static inline uint32_t cvmx_usb_read_csr32(struct cvmx_usb_state *usb,
- uint64_t address)
+static inline u32 cvmx_usb_read_csr32(struct octeon_hcd *usb, u64 address)
{
- uint32_t result = cvmx_read64_uint32(address ^ 4);
+ u32 result = cvmx_read64_uint32(address ^ 4);
return result;
}
-
/**
* Write a USB 32bit CSR. It performs the necessary address
* swizzle for 32bit CSRs and logs the value in a readable format
@@ -579,8 +555,8 @@ static inline uint32_t cvmx_usb_read_csr32(struct cvmx_usb_state *usb,
* @address: 64bit address to write
* @value: Value to write
*/
-static inline void cvmx_usb_write_csr32(struct cvmx_usb_state *usb,
- uint64_t address, uint32_t value)
+static inline void cvmx_usb_write_csr32(struct octeon_hcd *usb,
+ u64 address, u32 value)
{
cvmx_write64_uint32(address ^ 4, value);
cvmx_read64_uint64(CVMX_USBNX_DMA0_INB_CHN0(usb->index));
@@ -595,14 +571,13 @@ static inline void cvmx_usb_write_csr32(struct cvmx_usb_state *usb,
*
* Returns: Non zero if we need to do split transactions
*/
-static inline int cvmx_usb_pipe_needs_split(struct cvmx_usb_state *usb,
+static inline int cvmx_usb_pipe_needs_split(struct octeon_hcd *usb,
struct cvmx_usb_pipe *pipe)
{
return pipe->device_speed != CVMX_USB_SPEED_HIGH &&
usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH;
}
-
/**
* Trivial utility function to return the correct PID for a pipe
*
@@ -617,7 +592,7 @@ static inline int cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe)
return 0; /* Data0 */
}
-static void cvmx_fifo_setup(struct cvmx_usb_state *usb)
+static void cvmx_fifo_setup(struct octeon_hcd *usb)
{
union cvmx_usbcx_ghwcfg3 usbcx_ghwcfg3;
union cvmx_usbcx_gnptxfsiz npsiz;
@@ -675,7 +650,7 @@ static void cvmx_fifo_setup(struct cvmx_usb_state *usb)
*
* Returns: 0 or a negative error code.
*/
-static int cvmx_usb_shutdown(struct cvmx_usb_state *usb)
+static int cvmx_usb_shutdown(struct octeon_hcd *usb)
{
union cvmx_usbnx_clk_ctl usbn_clk_ctl;
@@ -704,12 +679,12 @@ static int cvmx_usb_shutdown(struct cvmx_usb_state *usb)
* off in the disabled state.
*
* @dev: Pointer to struct device for logging purposes.
- * @usb: Pointer to struct cvmx_usb_state.
+ * @usb: Pointer to struct octeon_hcd.
*
* Returns: 0 or a negative error code.
*/
static int cvmx_usb_initialize(struct device *dev,
- struct cvmx_usb_state *usb)
+ struct octeon_hcd *usb)
{
int channel;
int divisor;
@@ -975,7 +950,7 @@ retry:
*
* @usb: USB device state populated by cvmx_usb_initialize().
*/
-static void cvmx_usb_reset_port(struct cvmx_usb_state *usb)
+static void cvmx_usb_reset_port(struct octeon_hcd *usb)
{
usb->usbcx_hprt.u32 = cvmx_usb_read_csr32(usb,
CVMX_USBCX_HPRT(usb->index));
@@ -1002,7 +977,6 @@ static void cvmx_usb_reset_port(struct cvmx_usb_state *usb)
CVMX_USBCX_HPRT(usb->index));
}
-
/**
* Disable a USB port. After this call the USB port will not
* generate data transfers and will not generate events.
@@ -1013,7 +987,7 @@ static void cvmx_usb_reset_port(struct cvmx_usb_state *usb)
*
* Returns: 0 or a negative error code.
*/
-static int cvmx_usb_disable(struct cvmx_usb_state *usb)
+static int cvmx_usb_disable(struct octeon_hcd *usb)
{
/* Disable the port */
USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index), cvmx_usbcx_hprt,
@@ -1021,7 +995,6 @@ static int cvmx_usb_disable(struct cvmx_usb_state *usb)
return 0;
}
-
/**
* Get the current state of the USB port. Use this call to
* determine if the usb port has anything connected, is enabled,
@@ -1033,8 +1006,7 @@ static int cvmx_usb_disable(struct cvmx_usb_state *usb)
*
* Returns: Port status information
*/
-static struct cvmx_usb_port_status cvmx_usb_get_status(
- struct cvmx_usb_state *usb)
+static struct cvmx_usb_port_status cvmx_usb_get_status(struct octeon_hcd *usb)
{
union cvmx_usbcx_hprt usbc_hprt;
struct cvmx_usb_port_status result;
@@ -1048,7 +1020,7 @@ static struct cvmx_usb_port_status cvmx_usb_get_status(
result.port_speed = usbc_hprt.s.prtspd;
result.connected = usbc_hprt.s.prtconnsts;
result.connect_change =
- (result.connected != usb->port_status.connected);
+ result.connected != usb->port_status.connected;
return result;
}
@@ -1105,7 +1077,7 @@ 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,
+static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct octeon_hcd *usb,
int device_addr,
int endpoint_num,
enum cvmx_usb_speed
@@ -1125,8 +1097,8 @@ static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
if (!pipe)
return NULL;
if ((device_speed == CVMX_USB_SPEED_HIGH) &&
- (transfer_dir == CVMX_USB_DIRECTION_OUT) &&
- (transfer_type == CVMX_USB_TRANSFER_BULK))
+ (transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+ (transfer_type == CVMX_USB_TRANSFER_BULK))
pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
pipe->device_addr = device_addr;
pipe->endpoint_num = endpoint_num;
@@ -1143,9 +1115,9 @@ static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
if (!interval)
interval = 1;
if (cvmx_usb_pipe_needs_split(usb, pipe)) {
- pipe->interval = interval*8;
+ pipe->interval = interval * 8;
/* Force start splits to be schedule on uFrame 0 */
- pipe->next_tx_frame = ((usb->frame_number+7)&~7) +
+ pipe->next_tx_frame = ((usb->frame_number + 7) & ~7) +
pipe->interval;
} else {
pipe->interval = interval;
@@ -1166,7 +1138,6 @@ static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
return pipe;
}
-
/**
* Poll the RX FIFOs and remove data as needed. This function is only used
* in non DMA mode. It is very important that this function be called quickly
@@ -1174,13 +1145,13 @@ static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
*
* @usb: USB device state populated by cvmx_usb_initialize().
*/
-static void cvmx_usb_poll_rx_fifo(struct cvmx_usb_state *usb)
+static void cvmx_usb_poll_rx_fifo(struct octeon_hcd *usb)
{
union cvmx_usbcx_grxstsph rx_status;
int channel;
int bytes;
- uint64_t address;
- uint32_t *ptr;
+ u64 address;
+ u32 *ptr;
rx_status.u32 = cvmx_usb_read_csr32(usb,
CVMX_USBCX_GRXSTSPH(usb->index));
@@ -1213,7 +1184,6 @@ static void cvmx_usb_poll_rx_fifo(struct cvmx_usb_state *usb)
CVMX_SYNCW;
}
-
/**
* Fill the TX hardware fifo with data out of the software
* fifos
@@ -1225,7 +1195,7 @@ static void cvmx_usb_poll_rx_fifo(struct cvmx_usb_state *usb)
* Returns: Non zero if the hardware fifo was too small and needs
* to be serviced again.
*/
-static int cvmx_usb_fill_tx_hw(struct cvmx_usb_state *usb,
+static int cvmx_usb_fill_tx_hw(struct octeon_hcd *usb,
struct cvmx_usb_tx_fifo *fifo, int available)
{
/*
@@ -1234,9 +1204,9 @@ static int cvmx_usb_fill_tx_hw(struct cvmx_usb_state *usb,
*/
while (available && (fifo->head != fifo->tail)) {
int i = fifo->tail;
- const uint32_t *ptr = cvmx_phys_to_ptr(fifo->entry[i].address);
- uint64_t csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel,
- usb->index) ^ 4;
+ const u32 *ptr = cvmx_phys_to_ptr(fifo->entry[i].address);
+ u64 csr_address = USB_FIFO_ADDRESS(fifo->entry[i].channel,
+ usb->index) ^ 4;
int words = available;
/* Limit the amount of data to what the SW fifo has */
@@ -1275,13 +1245,12 @@ static int cvmx_usb_fill_tx_hw(struct cvmx_usb_state *usb,
return fifo->head != fifo->tail;
}
-
/**
* Check the hardware FIFOs and fill them as needed
*
* @usb: USB device state populated by cvmx_usb_initialize().
*/
-static void cvmx_usb_poll_tx_fifo(struct cvmx_usb_state *usb)
+static void cvmx_usb_poll_tx_fifo(struct octeon_hcd *usb)
{
if (usb->periodic.head != usb->periodic.tail) {
union cvmx_usbcx_hptxsts tx_status;
@@ -1312,14 +1281,13 @@ static void cvmx_usb_poll_tx_fifo(struct cvmx_usb_state *usb)
}
}
-
/**
* Fill the TX FIFO with an outgoing packet
*
* @usb: USB device state populated by cvmx_usb_initialize().
* @channel: Channel number to get packet from
*/
-static void cvmx_usb_fill_tx_fifo(struct cvmx_usb_state *usb, int channel)
+static void cvmx_usb_fill_tx_fifo(struct octeon_hcd *usb, int channel)
{
union cvmx_usbcx_hccharx hcchar;
union cvmx_usbcx_hcspltx usbc_hcsplt;
@@ -1348,7 +1316,7 @@ static void cvmx_usb_fill_tx_fifo(struct cvmx_usb_state *usb, int channel)
return;
if ((hcchar.s.eptype == CVMX_USB_TRANSFER_INTERRUPT) ||
- (hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS))
+ (hcchar.s.eptype == CVMX_USB_TRANSFER_ISOCHRONOUS))
fifo = &usb->periodic;
else
fifo = &usb->nonperiodic;
@@ -1357,7 +1325,7 @@ static void cvmx_usb_fill_tx_fifo(struct cvmx_usb_state *usb, int channel)
fifo->entry[fifo->head].address =
cvmx_read64_uint64(CVMX_USBNX_DMA0_OUTB_CHN0(usb->index) +
channel * 8);
- fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize+3)>>2;
+ fifo->entry[fifo->head].size = (usbc_hctsiz.s.xfersize + 3) >> 2;
fifo->head++;
if (fifo->head > MAX_CHANNELS)
fifo->head = 0;
@@ -1373,12 +1341,11 @@ static void cvmx_usb_fill_tx_fifo(struct cvmx_usb_state *usb, int channel)
* @channel: Channel to setup
* @pipe: Pipe for control transaction
*/
-static void cvmx_usb_start_channel_control(struct cvmx_usb_state *usb,
+static void cvmx_usb_start_channel_control(struct octeon_hcd *usb,
int channel,
struct cvmx_usb_pipe *pipe)
{
- struct octeon_hcd *priv = cvmx_usb_to_octeon(usb);
- struct usb_hcd *hcd = octeon_to_hcd(priv);
+ struct usb_hcd *hcd = octeon_to_hcd(usb);
struct device *dev = hcd->self.controller;
struct cvmx_usb_transaction *transaction =
list_first_entry(&pipe->transactions, typeof(*transaction),
@@ -1488,9 +1455,9 @@ static void cvmx_usb_start_channel_control(struct cvmx_usb_state *usb,
*/
packets_to_transfer = DIV_ROUND_UP(bytes_to_transfer,
pipe->max_packet);
- if (packets_to_transfer == 0)
+ if (packets_to_transfer == 0) {
packets_to_transfer = 1;
- else if ((packets_to_transfer > 1) &&
+ } else if ((packets_to_transfer > 1) &&
(usb->init_flags & CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
/*
* Limit to one packet when not using DMA. Channels must be
@@ -1515,7 +1482,6 @@ static void cvmx_usb_start_channel_control(struct cvmx_usb_state *usb,
usbc_hctsiz.u32);
}
-
/**
* Start a channel to perform the pipe's head transaction
*
@@ -1523,7 +1489,7 @@ static void cvmx_usb_start_channel_control(struct cvmx_usb_state *usb,
* @channel: Channel to setup
* @pipe: Pipe to start
*/
-static void cvmx_usb_start_channel(struct cvmx_usb_state *usb, int channel,
+static void cvmx_usb_start_channel(struct octeon_hcd *usb, int channel,
struct cvmx_usb_pipe *pipe)
{
struct cvmx_usb_transaction *transaction =
@@ -1539,7 +1505,7 @@ static void cvmx_usb_start_channel(struct cvmx_usb_state *usb, int channel,
pipe->flags |= CVMX_USB_PIPE_FLAGS_SCHEDULED;
/* Mark this channel as in use */
- usb->idle_hardware_channels &= ~(1<<channel);
+ usb->idle_hardware_channels &= ~(1 << channel);
/* Enable the channel interrupt bits */
{
@@ -1579,22 +1545,22 @@ static void cvmx_usb_start_channel(struct cvmx_usb_state *usb, int channel,
usbc_hcintmsk.s.xfercomplmsk = 1;
}
cvmx_usb_write_csr32(usb,
- CVMX_USBCX_HCINTMSKX(channel, usb->index),
- usbc_hcintmsk.u32);
+ 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.s.haintmsk |= 1<<channel;
+ usbc_haintmsk.s.haintmsk |= 1 << channel;
cvmx_usb_write_csr32(usb, CVMX_USBCX_HAINTMSK(usb->index),
usbc_haintmsk.u32);
}
/* Setup the location the DMA engine uses. */
{
- uint64_t reg;
- uint64_t dma_address = transaction->buffer +
- transaction->actual_bytes;
+ u64 reg;
+ u64 dma_address = transaction->buffer +
+ transaction->actual_bytes;
if (transaction->type == CVMX_USB_TRANSFER_ISOCHRONOUS)
dma_address = transaction->buffer +
@@ -1636,15 +1602,16 @@ static void cvmx_usb_start_channel(struct cvmx_usb_state *usb, int channel,
* We only store the lower two bits since the time ahead
* can only be two frames
*/
- if ((transaction->stage&1) == 0) {
+ if ((transaction->stage & 1) == 0) {
if (transaction->type == CVMX_USB_TRANSFER_BULK)
pipe->split_sc_frame =
(usb->frame_number + 1) & 0x7f;
else
pipe->split_sc_frame =
(usb->frame_number + 2) & 0x7f;
- } else
+ } else {
pipe->split_sc_frame = -1;
+ }
usbc_hcsplt.s.spltena = 1;
usbc_hcsplt.s.hubaddr = pipe->hub_device_addr;
@@ -1666,10 +1633,9 @@ static void cvmx_usb_start_channel(struct cvmx_usb_state *usb, int channel,
* begin/middle/end of the data or all
*/
if (!usbc_hcsplt.s.compsplt &&
- (pipe->transfer_dir ==
- CVMX_USB_DIRECTION_OUT) &&
- (pipe->transfer_type ==
- CVMX_USB_TRANSFER_ISOCHRONOUS)) {
+ (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+ (pipe->transfer_type ==
+ CVMX_USB_TRANSFER_ISOCHRONOUS)) {
/*
* Clear the split complete frame number as
* there isn't going to be a split complete
@@ -1732,11 +1698,11 @@ static void cvmx_usb_start_channel(struct cvmx_usb_state *usb, int channel,
*/
packets_to_transfer =
DIV_ROUND_UP(bytes_to_transfer, pipe->max_packet);
- if (packets_to_transfer == 0)
+ if (packets_to_transfer == 0) {
packets_to_transfer = 1;
- else if ((packets_to_transfer > 1) &&
- (usb->init_flags &
- CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
+ } else if ((packets_to_transfer > 1) &&
+ (usb->init_flags &
+ CVMX_USB_INITIALIZE_FLAGS_NO_DMA)) {
/*
* Limit to one packet when not using DMA. Channels must
* be restarted between every packet for IN
@@ -1783,7 +1749,7 @@ static void cvmx_usb_start_channel(struct cvmx_usb_state *usb, int channel,
* Set the startframe odd/even properly. This is only used for
* periodic
*/
- usbc_hcchar.s.oddfrm = usb->frame_number&1;
+ usbc_hcchar.s.oddfrm = usb->frame_number & 1;
/*
* Set the number of back to back packets allowed by this
@@ -1843,9 +1809,11 @@ static void cvmx_usb_start_channel(struct cvmx_usb_state *usb, int channel,
break;
}
{
- union cvmx_usbcx_hctsizx usbc_hctsiz = {.u32 =
+ union cvmx_usbcx_hctsizx usbc_hctsiz = { .u32 =
cvmx_usb_read_csr32(usb,
- CVMX_USBCX_HCTSIZX(channel, usb->index))};
+ CVMX_USBCX_HCTSIZX(channel,
+ usb->index))
+ };
transaction->xfersize = usbc_hctsiz.s.xfersize;
transaction->pktcnt = usbc_hctsiz.s.pktcnt;
}
@@ -1858,21 +1826,19 @@ static void cvmx_usb_start_channel(struct cvmx_usb_state *usb, int channel,
cvmx_usb_fill_tx_fifo(usb, channel);
}
-
/**
* Find a pipe that is ready to be scheduled to hardware.
* @usb: USB device state populated by cvmx_usb_initialize().
- * @list: Pipe list to search
- * @current_frame:
- * Frame counter to use as a time reference.
+ * @xfer_type: Transfer type
*
* Returns: Pipe or NULL if none are ready
*/
static struct cvmx_usb_pipe *cvmx_usb_find_ready_pipe(
- struct cvmx_usb_state *usb,
- struct list_head *list,
- uint64_t current_frame)
+ struct octeon_hcd *usb,
+ enum cvmx_usb_transfer xfer_type)
{
+ struct list_head *list = usb->active_pipes + xfer_type;
+ u64 current_frame = usb->frame_number;
struct cvmx_usb_pipe *pipe;
list_for_each_entry(pipe, list, node) {
@@ -1880,11 +1846,11 @@ static struct cvmx_usb_pipe *cvmx_usb_find_ready_pipe(
list_first_entry(&pipe->transactions, typeof(*t),
node);
if (!(pipe->flags & CVMX_USB_PIPE_FLAGS_SCHEDULED) && t &&
- (pipe->next_tx_frame <= current_frame) &&
- ((pipe->split_sc_frame == -1) ||
- ((((int)current_frame - (int)pipe->split_sc_frame)
- & 0x7f) < 0x40)) &&
- (!usb->active_split || (usb->active_split == t))) {
+ (pipe->next_tx_frame <= current_frame) &&
+ ((pipe->split_sc_frame == -1) ||
+ ((((int)current_frame - pipe->split_sc_frame) & 0x7f) <
+ 0x40)) &&
+ (!usb->active_split || (usb->active_split == t))) {
prefetch(t);
return pipe;
}
@@ -1892,6 +1858,32 @@ static struct cvmx_usb_pipe *cvmx_usb_find_ready_pipe(
return NULL;
}
+static struct cvmx_usb_pipe *cvmx_usb_next_pipe(struct octeon_hcd *usb,
+ int is_sof)
+{
+ struct cvmx_usb_pipe *pipe;
+
+ /* Find a pipe needing service. */
+ if (is_sof) {
+ /*
+ * Only process periodic pipes on SOF interrupts. This way we
+ * are sure that the periodic data is sent in the beginning of
+ * the frame.
+ */
+ pipe = cvmx_usb_find_ready_pipe(usb,
+ CVMX_USB_TRANSFER_ISOCHRONOUS);
+ if (pipe)
+ return pipe;
+ pipe = cvmx_usb_find_ready_pipe(usb,
+ CVMX_USB_TRANSFER_INTERRUPT);
+ if (pipe)
+ return pipe;
+ }
+ pipe = cvmx_usb_find_ready_pipe(usb, CVMX_USB_TRANSFER_CONTROL);
+ if (pipe)
+ return pipe;
+ return cvmx_usb_find_ready_pipe(usb, CVMX_USB_TRANSFER_BULK);
+}
/**
* Called whenever a pipe might need to be scheduled to the
@@ -1900,7 +1892,7 @@ static struct cvmx_usb_pipe *cvmx_usb_find_ready_pipe(
* @usb: USB device state populated by cvmx_usb_initialize().
* @is_sof: True if this schedule was called on a SOF interrupt.
*/
-static void cvmx_usb_schedule(struct cvmx_usb_state *usb, int is_sof)
+static void cvmx_usb_schedule(struct octeon_hcd *usb, int is_sof)
{
int channel;
struct cvmx_usb_pipe *pipe;
@@ -1922,7 +1914,7 @@ static void cvmx_usb_schedule(struct cvmx_usb_state *usb, int is_sof)
CVMX_USBCX_HFIR(usb->index))
};
- if (hfnum.s.frrem < hfir.s.frint/4)
+ if (hfnum.s.frrem < hfir.s.frint / 4)
goto done;
}
@@ -1932,35 +1924,7 @@ static void cvmx_usb_schedule(struct cvmx_usb_state *usb, int is_sof)
if (unlikely(channel > 7))
break;
- /* Find a pipe needing service */
- pipe = NULL;
- if (is_sof) {
- /*
- * Only process periodic pipes on SOF interrupts. This
- * way we are sure that the periodic data is sent in the
- * beginning of the frame
- */
- pipe = cvmx_usb_find_ready_pipe(usb,
- usb->active_pipes +
- CVMX_USB_TRANSFER_ISOCHRONOUS,
- usb->frame_number);
- if (likely(!pipe))
- pipe = cvmx_usb_find_ready_pipe(usb,
- usb->active_pipes +
- CVMX_USB_TRANSFER_INTERRUPT,
- usb->frame_number);
- }
- if (likely(!pipe)) {
- pipe = cvmx_usb_find_ready_pipe(usb,
- usb->active_pipes +
- CVMX_USB_TRANSFER_CONTROL,
- usb->frame_number);
- if (likely(!pipe))
- pipe = cvmx_usb_find_ready_pipe(usb,
- usb->active_pipes +
- CVMX_USB_TRANSFER_BULK,
- usb->frame_number);
- }
+ pipe = cvmx_usb_next_pipe(usb, is_sof);
if (!pipe)
break;
@@ -1974,7 +1938,7 @@ done:
*/
need_sof = 0;
for (ttype = CVMX_USB_TRANSFER_CONTROL;
- ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
+ ttype <= CVMX_USB_TRANSFER_INTERRUPT; ttype++) {
list_for_each_entry(pipe, &usb->active_pipes[ttype], node) {
if (pipe->next_tx_frame > usb->frame_number) {
need_sof = 1;
@@ -1986,19 +1950,18 @@ done:
cvmx_usbcx_gintmsk, sofmsk, need_sof);
}
-static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
- enum cvmx_usb_complete status,
+static void octeon_usb_urb_complete_callback(struct octeon_hcd *usb,
+ enum cvmx_usb_status status,
struct cvmx_usb_pipe *pipe,
struct cvmx_usb_transaction
*transaction,
int bytes_transferred,
struct urb *urb)
{
- struct octeon_hcd *priv = cvmx_usb_to_octeon(usb);
- struct usb_hcd *hcd = octeon_to_hcd(priv);
+ struct usb_hcd *hcd = octeon_to_hcd(usb);
struct device *dev = hcd->self.controller;
- if (likely(status == CVMX_USB_COMPLETE_SUCCESS))
+ if (likely(status == CVMX_USB_STATUS_OK))
urb->actual_length = bytes_transferred;
else
urb->actual_length = 0;
@@ -2006,7 +1969,8 @@ static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
urb->hcpriv = NULL;
/* For Isochronous transactions we need to update the URB packet status
- list from data in our private copy */
+ * list from data in our private copy
+ */
if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
int i;
/*
@@ -2014,12 +1978,11 @@ static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
* field.
*/
struct cvmx_usb_iso_packet *iso_packet =
- (struct cvmx_usb_iso_packet *) urb->setup_packet;
+ (struct cvmx_usb_iso_packet *)urb->setup_packet;
/* Recalculate the transfer size by adding up each packet */
urb->actual_length = 0;
for (i = 0; i < urb->number_of_packets; i++) {
- if (iso_packet[i].status ==
- CVMX_USB_COMPLETE_SUCCESS) {
+ if (iso_packet[i].status == CVMX_USB_STATUS_OK) {
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length =
iso_packet[i].length;
@@ -2039,41 +2002,41 @@ static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
}
switch (status) {
- case CVMX_USB_COMPLETE_SUCCESS:
+ case CVMX_USB_STATUS_OK:
urb->status = 0;
break;
- case CVMX_USB_COMPLETE_CANCEL:
+ case CVMX_USB_STATUS_CANCEL:
if (urb->status == 0)
urb->status = -ENOENT;
break;
- case CVMX_USB_COMPLETE_STALL:
+ case CVMX_USB_STATUS_STALL:
dev_dbg(dev, "status=stall pipe=%p transaction=%p size=%d\n",
pipe, transaction, bytes_transferred);
urb->status = -EPIPE;
break;
- case CVMX_USB_COMPLETE_BABBLEERR:
+ case CVMX_USB_STATUS_BABBLEERR:
dev_dbg(dev, "status=babble pipe=%p transaction=%p size=%d\n",
pipe, transaction, bytes_transferred);
urb->status = -EPIPE;
break;
- case CVMX_USB_COMPLETE_SHORT:
+ case CVMX_USB_STATUS_SHORT:
dev_dbg(dev, "status=short pipe=%p transaction=%p size=%d\n",
pipe, transaction, bytes_transferred);
urb->status = -EREMOTEIO;
break;
- case CVMX_USB_COMPLETE_ERROR:
- case CVMX_USB_COMPLETE_XACTERR:
- case CVMX_USB_COMPLETE_DATATGLERR:
- case CVMX_USB_COMPLETE_FRAMEERR:
+ case CVMX_USB_STATUS_ERROR:
+ case CVMX_USB_STATUS_XACTERR:
+ case CVMX_USB_STATUS_DATATGLERR:
+ case CVMX_USB_STATUS_FRAMEERR:
dev_dbg(dev, "status=%d pipe=%p transaction=%p size=%d\n",
status, pipe, transaction, bytes_transferred);
urb->status = -EPROTO;
break;
}
- usb_hcd_unlink_urb_from_ep(octeon_to_hcd(priv), urb);
- spin_unlock(&priv->lock);
- usb_hcd_giveback_urb(octeon_to_hcd(priv), urb, urb->status);
- spin_lock(&priv->lock);
+ usb_hcd_unlink_urb_from_ep(octeon_to_hcd(usb), urb);
+ spin_unlock(&usb->lock);
+ usb_hcd_giveback_urb(octeon_to_hcd(usb), urb, urb->status);
+ spin_lock(&usb->lock);
}
/**
@@ -2087,10 +2050,10 @@ static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
* @complete_code:
* Completion code
*/
-static void cvmx_usb_perform_complete(struct cvmx_usb_state *usb,
- struct cvmx_usb_pipe *pipe,
- struct cvmx_usb_transaction *transaction,
- enum cvmx_usb_complete complete_code)
+static void cvmx_usb_complete(struct octeon_hcd *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct cvmx_usb_transaction *transaction,
+ enum cvmx_usb_status complete_code)
{
/* If this was a split then clear our split in progress marker */
if (usb->active_split == transaction)
@@ -2110,7 +2073,7 @@ static void cvmx_usb_perform_complete(struct cvmx_usb_state *usb,
* next one
*/
if ((transaction->iso_number_packets > 1) &&
- (complete_code == CVMX_USB_COMPLETE_SUCCESS)) {
+ (complete_code == CVMX_USB_STATUS_OK)) {
/* No bytes transferred for this packet as of yet */
transaction->actual_bytes = 0;
/* One less ISO waiting to transfer */
@@ -2133,7 +2096,6 @@ static void cvmx_usb_perform_complete(struct cvmx_usb_state *usb,
kfree(transaction);
}
-
/**
* Submit a usb transaction to a pipe. Called for all types
* of transactions.
@@ -2157,12 +2119,12 @@ static void cvmx_usb_perform_complete(struct cvmx_usb_state *usb,
* Returns: Transaction or NULL on failure.
*/
static struct cvmx_usb_transaction *cvmx_usb_submit_transaction(
- struct cvmx_usb_state *usb,
+ struct octeon_hcd *usb,
struct cvmx_usb_pipe *pipe,
enum cvmx_usb_transfer type,
- uint64_t buffer,
+ u64 buffer,
int buffer_length,
- uint64_t control_header,
+ u64 control_header,
int iso_start_frame,
int iso_number_packets,
struct cvmx_usb_iso_packet *iso_packets,
@@ -2208,7 +2170,6 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_transaction(
return transaction;
}
-
/**
* Call to submit a USB Bulk transfer to a pipe.
*
@@ -2219,7 +2180,7 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_transaction(
* Returns: A submitted transaction or NULL on failure.
*/
static struct cvmx_usb_transaction *cvmx_usb_submit_bulk(
- struct cvmx_usb_state *usb,
+ struct octeon_hcd *usb,
struct cvmx_usb_pipe *pipe,
struct urb *urb)
{
@@ -2233,7 +2194,6 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_bulk(
urb);
}
-
/**
* Call to submit a USB Interrupt transfer to a pipe.
*
@@ -2244,7 +2204,7 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_bulk(
* Returns: A submitted transaction or NULL on failure.
*/
static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(
- struct cvmx_usb_state *usb,
+ struct octeon_hcd *usb,
struct cvmx_usb_pipe *pipe,
struct urb *urb)
{
@@ -2259,7 +2219,6 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(
urb);
}
-
/**
* Call to submit a USB Control transfer to a pipe.
*
@@ -2270,12 +2229,12 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(
* Returns: A submitted transaction or NULL on failure.
*/
static struct cvmx_usb_transaction *cvmx_usb_submit_control(
- struct cvmx_usb_state *usb,
+ struct octeon_hcd *usb,
struct cvmx_usb_pipe *pipe,
struct urb *urb)
{
int buffer_length = urb->transfer_buffer_length;
- uint64_t control_header = urb->setup_dma;
+ u64 control_header = urb->setup_dma;
struct usb_ctrlrequest *header = cvmx_phys_to_ptr(control_header);
if ((header->bRequestType & USB_DIR_IN) == 0)
@@ -2291,7 +2250,6 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_control(
urb);
}
-
/**
* Call to submit a USB Isochronous transfer to a pipe.
*
@@ -2302,13 +2260,13 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_control(
* Returns: A submitted transaction or NULL on failure.
*/
static struct cvmx_usb_transaction *cvmx_usb_submit_isochronous(
- struct cvmx_usb_state *usb,
+ struct octeon_hcd *usb,
struct cvmx_usb_pipe *pipe,
struct urb *urb)
{
struct cvmx_usb_iso_packet *packets;
- packets = (struct cvmx_usb_iso_packet *) urb->setup_packet;
+ packets = (struct cvmx_usb_iso_packet *)urb->setup_packet;
return cvmx_usb_submit_transaction(usb, pipe,
CVMX_USB_TRANSFER_ISOCHRONOUS,
urb->transfer_dma,
@@ -2319,7 +2277,6 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_isochronous(
packets, urb);
}
-
/**
* Cancel one outstanding request in a pipe. Canceling a request
* can fail if the transaction has already completed before cancel
@@ -2333,7 +2290,7 @@ static struct cvmx_usb_transaction *cvmx_usb_submit_isochronous(
*
* Returns: 0 or a negative error code.
*/
-static int cvmx_usb_cancel(struct cvmx_usb_state *usb,
+static int cvmx_usb_cancel(struct octeon_hcd *usb,
struct cvmx_usb_pipe *pipe,
struct cvmx_usb_transaction *transaction)
{
@@ -2359,17 +2316,15 @@ static int cvmx_usb_cancel(struct cvmx_usb_state *usb,
if (usbc_hcchar.s.chena) {
usbc_hcchar.s.chdis = 1;
cvmx_usb_write_csr32(usb,
- CVMX_USBCX_HCCHARX(pipe->channel,
- usb->index),
- usbc_hcchar.u32);
+ CVMX_USBCX_HCCHARX(pipe->channel,
+ usb->index),
+ usbc_hcchar.u32);
}
}
- cvmx_usb_perform_complete(usb, pipe, transaction,
- CVMX_USB_COMPLETE_CANCEL);
+ cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_CANCEL);
return 0;
}
-
/**
* Cancel all outstanding requests in a pipe. Logically all this
* does is call cvmx_usb_cancel() in a loop.
@@ -2379,7 +2334,7 @@ static int cvmx_usb_cancel(struct cvmx_usb_state *usb,
*
* Returns: 0 or a negative error code.
*/
-static int cvmx_usb_cancel_all(struct cvmx_usb_state *usb,
+static int cvmx_usb_cancel_all(struct octeon_hcd *usb,
struct cvmx_usb_pipe *pipe)
{
struct cvmx_usb_transaction *transaction, *next;
@@ -2394,7 +2349,6 @@ static int cvmx_usb_cancel_all(struct cvmx_usb_state *usb,
return 0;
}
-
/**
* Close a pipe created with cvmx_usb_open_pipe().
*
@@ -2404,7 +2358,7 @@ static int cvmx_usb_cancel_all(struct cvmx_usb_state *usb,
* Returns: 0 or a negative error code. EBUSY is returned if the pipe has
* outstanding transfers.
*/
-static int cvmx_usb_close_pipe(struct cvmx_usb_state *usb,
+static int cvmx_usb_close_pipe(struct octeon_hcd *usb,
struct cvmx_usb_pipe *pipe)
{
/* Fail if the pipe has pending transactions */
@@ -2425,7 +2379,7 @@ static int cvmx_usb_close_pipe(struct cvmx_usb_state *usb,
*
* Returns: USB frame number
*/
-static int cvmx_usb_get_frame_number(struct cvmx_usb_state *usb)
+static int cvmx_usb_get_frame_number(struct octeon_hcd *usb)
{
int frame_number;
union cvmx_usbcx_hfnum usbc_hfnum;
@@ -2436,6 +2390,197 @@ static int cvmx_usb_get_frame_number(struct cvmx_usb_state *usb)
return frame_number;
}
+static void cvmx_usb_transfer_control(struct octeon_hcd *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct cvmx_usb_transaction *transaction,
+ union cvmx_usbcx_hccharx usbc_hcchar,
+ int buffer_space_left,
+ int bytes_in_last_packet)
+{
+ switch (transaction->stage) {
+ case CVMX_USB_STAGE_NON_CONTROL:
+ case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
+ /* This should be impossible */
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_ERROR);
+ break;
+ case CVMX_USB_STAGE_SETUP:
+ pipe->pid_toggle = 1;
+ if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+ transaction->stage =
+ CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE;
+ } else {
+ struct usb_ctrlrequest *header =
+ cvmx_phys_to_ptr(transaction->control_header);
+ if (header->wLength)
+ transaction->stage = CVMX_USB_STAGE_DATA;
+ else
+ transaction->stage = CVMX_USB_STAGE_STATUS;
+ }
+ break;
+ case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
+ {
+ struct usb_ctrlrequest *header =
+ cvmx_phys_to_ptr(transaction->control_header);
+ if (header->wLength)
+ transaction->stage = CVMX_USB_STAGE_DATA;
+ else
+ transaction->stage = CVMX_USB_STAGE_STATUS;
+ }
+ break;
+ case CVMX_USB_STAGE_DATA:
+ if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+ transaction->stage = CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
+ /*
+ * For setup OUT data that are splits,
+ * the hardware doesn't appear to count
+ * transferred data. Here we manually
+ * update the data transferred
+ */
+ if (!usbc_hcchar.s.epdir) {
+ if (buffer_space_left < pipe->max_packet)
+ transaction->actual_bytes +=
+ buffer_space_left;
+ else
+ transaction->actual_bytes +=
+ pipe->max_packet;
+ }
+ } else if ((buffer_space_left == 0) ||
+ (bytes_in_last_packet < pipe->max_packet)) {
+ pipe->pid_toggle = 1;
+ transaction->stage = CVMX_USB_STAGE_STATUS;
+ }
+ break;
+ case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
+ if ((buffer_space_left == 0) ||
+ (bytes_in_last_packet < pipe->max_packet)) {
+ pipe->pid_toggle = 1;
+ transaction->stage = CVMX_USB_STAGE_STATUS;
+ } else {
+ transaction->stage = CVMX_USB_STAGE_DATA;
+ }
+ break;
+ case CVMX_USB_STAGE_STATUS:
+ if (cvmx_usb_pipe_needs_split(usb, pipe))
+ transaction->stage =
+ CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE;
+ else
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_OK);
+ break;
+ case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
+ cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK);
+ break;
+ }
+}
+
+static void cvmx_usb_transfer_bulk(struct octeon_hcd *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct cvmx_usb_transaction *transaction,
+ union cvmx_usbcx_hcintx usbc_hcint,
+ int buffer_space_left,
+ int bytes_in_last_packet)
+{
+ /*
+ * The only time a bulk transfer isn't complete when it finishes with
+ * an ACK is during a split transaction. For splits we need to continue
+ * the transfer if more data is needed.
+ */
+ if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+ if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL)
+ transaction->stage =
+ CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+ else if (buffer_space_left &&
+ (bytes_in_last_packet == pipe->max_packet))
+ transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+ else
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_OK);
+ } else {
+ if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
+ (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) &&
+ (usbc_hcint.s.nak))
+ pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
+ if (!buffer_space_left ||
+ (bytes_in_last_packet < pipe->max_packet))
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_OK);
+ }
+}
+
+static void cvmx_usb_transfer_intr(struct octeon_hcd *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct cvmx_usb_transaction *transaction,
+ int buffer_space_left,
+ int bytes_in_last_packet)
+{
+ if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+ if (transaction->stage == CVMX_USB_STAGE_NON_CONTROL) {
+ transaction->stage =
+ CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+ } else if (buffer_space_left &&
+ (bytes_in_last_packet == pipe->max_packet)) {
+ transaction->stage = CVMX_USB_STAGE_NON_CONTROL;
+ } else {
+ pipe->next_tx_frame += pipe->interval;
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_OK);
+ }
+ } else if (!buffer_space_left ||
+ (bytes_in_last_packet < pipe->max_packet)) {
+ pipe->next_tx_frame += pipe->interval;
+ cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK);
+ }
+}
+
+static void cvmx_usb_transfer_isoc(struct octeon_hcd *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct cvmx_usb_transaction *transaction,
+ int buffer_space_left,
+ int bytes_in_last_packet,
+ int bytes_this_transfer)
+{
+ if (cvmx_usb_pipe_needs_split(usb, pipe)) {
+ /*
+ * ISOCHRONOUS OUT splits don't require a complete split stage.
+ * Instead they use a sequence of begin OUT splits to transfer
+ * the data 188 bytes at a time. Once the transfer is complete,
+ * the pipe sleeps until the next schedule interval.
+ */
+ if (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT) {
+ /*
+ * If no space left or this wasn't a max size packet
+ * then this transfer is complete. Otherwise start it
+ * again to send the next 188 bytes
+ */
+ if (!buffer_space_left || (bytes_this_transfer < 188)) {
+ pipe->next_tx_frame += pipe->interval;
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_OK);
+ }
+ return;
+ }
+ if (transaction->stage ==
+ CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
+ /*
+ * We are in the incoming data phase. Keep getting data
+ * until we run out of space or get a small packet
+ */
+ if ((buffer_space_left == 0) ||
+ (bytes_in_last_packet < pipe->max_packet)) {
+ pipe->next_tx_frame += pipe->interval;
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_OK);
+ }
+ } else {
+ transaction->stage =
+ CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
+ }
+ } else {
+ pipe->next_tx_frame += pipe->interval;
+ cvmx_usb_complete(usb, pipe, transaction, CVMX_USB_STATUS_OK);
+ }
+}
/**
* Poll a channel for status
@@ -2445,10 +2590,9 @@ static int cvmx_usb_get_frame_number(struct cvmx_usb_state *usb)
*
* Returns: Zero on success
*/
-static int cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
+static int cvmx_usb_poll_channel(struct octeon_hcd *usb, int channel)
{
- struct octeon_hcd *priv = cvmx_usb_to_octeon(usb);
- struct usb_hcd *hcd = octeon_to_hcd(priv);
+ struct usb_hcd *hcd = octeon_to_hcd(usb);
struct device *dev = hcd->self.controller;
union cvmx_usbcx_hcintx usbc_hcint;
union cvmx_usbcx_hctsizx usbc_hctsiz;
@@ -2475,9 +2619,9 @@ static int cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* write of HCCHARX without changing things
*/
cvmx_usb_write_csr32(usb,
- CVMX_USBCX_HCCHARX(channel,
- usb->index),
- usbc_hcchar.u32);
+ CVMX_USBCX_HCCHARX(channel,
+ usb->index),
+ usbc_hcchar.u32);
return 0;
}
@@ -2492,14 +2636,12 @@ static int cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
hcintmsk.u32 = 0;
hcintmsk.s.chhltdmsk = 1;
cvmx_usb_write_csr32(usb,
- CVMX_USBCX_HCINTMSKX(channel,
- usb->index),
- hcintmsk.u32);
+ CVMX_USBCX_HCINTMSKX(channel, usb->index),
+ hcintmsk.u32);
usbc_hcchar.s.chdis = 1;
cvmx_usb_write_csr32(usb,
- CVMX_USBCX_HCCHARX(channel,
- usb->index),
- usbc_hcchar.u32);
+ CVMX_USBCX_HCCHARX(channel, usb->index),
+ usbc_hcchar.u32);
return 0;
} else if (usbc_hcint.s.xfercompl) {
/*
@@ -2523,7 +2665,7 @@ 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);
- usb->idle_hardware_channels |= (1<<channel);
+ usb->idle_hardware_channels |= (1 << channel);
/* Make sure this channel is tied to a valid pipe */
pipe = usb->pipe_for_channel[channel];
@@ -2593,7 +2735,7 @@ static int cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* transferred
*/
if ((transaction->stage == CVMX_USB_STAGE_SETUP) ||
- (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE))
+ (transaction->stage == CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE))
bytes_this_transfer = 0;
/*
@@ -2621,8 +2763,8 @@ static int cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* will clear this flag
*/
if ((pipe->device_speed == CVMX_USB_SPEED_HIGH) &&
- (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
- (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
+ (pipe->transfer_type == CVMX_USB_TRANSFER_BULK) &&
+ (pipe->transfer_dir == CVMX_USB_DIRECTION_OUT))
pipe->flags |= CVMX_USB_PIPE_FLAGS_NEED_PING;
if (unlikely(WARN_ON_ONCE(bytes_this_transfer < 0))) {
@@ -2631,8 +2773,8 @@ static int cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* keeps substracting same byte count over and over again. In
* such case we just need to fail every transaction.
*/
- cvmx_usb_perform_complete(usb, pipe, transaction,
- CVMX_USB_COMPLETE_ERROR);
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_ERROR);
return 0;
}
@@ -2644,24 +2786,24 @@ static int cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* the actual bytes transferred
*/
pipe->pid_toggle = 0;
- cvmx_usb_perform_complete(usb, pipe, transaction,
- CVMX_USB_COMPLETE_STALL);
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_STALL);
} else if (usbc_hcint.s.xacterr) {
/*
* XactErr as a response means the device signaled
* something wrong with the transfer. For example, PID
* toggle errors cause these.
*/
- cvmx_usb_perform_complete(usb, pipe, transaction,
- CVMX_USB_COMPLETE_XACTERR);
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_XACTERR);
} else if (usbc_hcint.s.bblerr) {
/* Babble Error (BblErr) */
- cvmx_usb_perform_complete(usb, pipe, transaction,
- CVMX_USB_COMPLETE_BABBLEERR);
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_BABBLEERR);
} else if (usbc_hcint.s.datatglerr) {
/* Data toggle error */
- cvmx_usb_perform_complete(usb, pipe, transaction,
- CVMX_USB_COMPLETE_DATATGLERR);
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_DATATGLERR);
} else if (usbc_hcint.s.nyet) {
/*
* NYET as a response is only allowed in three cases: as a
@@ -2676,10 +2818,10 @@ static int cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* again. Otherwise this transaction is complete
*/
if ((buffer_space_left == 0) ||
- (bytes_in_last_packet < pipe->max_packet))
- cvmx_usb_perform_complete(usb, pipe,
- transaction,
- CVMX_USB_COMPLETE_SUCCESS);
+ (bytes_in_last_packet < pipe->max_packet))
+ cvmx_usb_complete(usb, pipe,
+ transaction,
+ CVMX_USB_STATUS_OK);
} else {
/*
* Split transactions retry the split complete 4 times
@@ -2713,205 +2855,26 @@ static int cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
switch (transaction->type) {
case CVMX_USB_TRANSFER_CONTROL:
- switch (transaction->stage) {
- case CVMX_USB_STAGE_NON_CONTROL:
- case CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE:
- /* This should be impossible */
- cvmx_usb_perform_complete(usb, pipe,
- transaction, CVMX_USB_COMPLETE_ERROR);
- break;
- case CVMX_USB_STAGE_SETUP:
- pipe->pid_toggle = 1;
- if (cvmx_usb_pipe_needs_split(usb, pipe))
- transaction->stage =
- CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE;
- else {
- struct usb_ctrlrequest *header =
- cvmx_phys_to_ptr(transaction->control_header);
- if (header->wLength)
- transaction->stage =
- CVMX_USB_STAGE_DATA;
- else
- transaction->stage =
- CVMX_USB_STAGE_STATUS;
- }
- break;
- case CVMX_USB_STAGE_SETUP_SPLIT_COMPLETE:
- {
- struct usb_ctrlrequest *header =
- cvmx_phys_to_ptr(transaction->control_header);
- if (header->wLength)
- transaction->stage =
- CVMX_USB_STAGE_DATA;
- else
- transaction->stage =
- CVMX_USB_STAGE_STATUS;
- }
- break;
- case CVMX_USB_STAGE_DATA:
- if (cvmx_usb_pipe_needs_split(usb, pipe)) {
- transaction->stage =
- CVMX_USB_STAGE_DATA_SPLIT_COMPLETE;
- /*
- * For setup OUT data that are splits,
- * the hardware doesn't appear to count
- * transferred data. Here we manually
- * update the data transferred
- */
- if (!usbc_hcchar.s.epdir) {
- if (buffer_space_left < pipe->max_packet)
- transaction->actual_bytes +=
- buffer_space_left;
- else
- transaction->actual_bytes +=
- pipe->max_packet;
- }
- } else if ((buffer_space_left == 0) ||
- (bytes_in_last_packet <
- pipe->max_packet)) {
- pipe->pid_toggle = 1;
- transaction->stage =
- CVMX_USB_STAGE_STATUS;
- }
- break;
- case CVMX_USB_STAGE_DATA_SPLIT_COMPLETE:
- if ((buffer_space_left == 0) ||
- (bytes_in_last_packet <
- pipe->max_packet)) {
- pipe->pid_toggle = 1;
- transaction->stage =
- CVMX_USB_STAGE_STATUS;
- } else {
- transaction->stage =
- CVMX_USB_STAGE_DATA;
- }
- break;
- case CVMX_USB_STAGE_STATUS:
- if (cvmx_usb_pipe_needs_split(usb, pipe))
- transaction->stage =
- CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE;
- else
- cvmx_usb_perform_complete(usb, pipe,
- transaction,
- CVMX_USB_COMPLETE_SUCCESS);
- break;
- case CVMX_USB_STAGE_STATUS_SPLIT_COMPLETE:
- cvmx_usb_perform_complete(usb, pipe,
- transaction,
- CVMX_USB_COMPLETE_SUCCESS);
- break;
- }
+ cvmx_usb_transfer_control(usb, pipe, transaction,
+ usbc_hcchar,
+ buffer_space_left,
+ bytes_in_last_packet);
break;
case CVMX_USB_TRANSFER_BULK:
+ cvmx_usb_transfer_bulk(usb, pipe, transaction,
+ usbc_hcint, buffer_space_left,
+ bytes_in_last_packet);
+ break;
case CVMX_USB_TRANSFER_INTERRUPT:
- /*
- * The only time a bulk transfer isn't complete when it
- * finishes with an ACK is during a split transaction.
- * For splits we need to continue the transfer if more
- * data is needed
- */
- if (cvmx_usb_pipe_needs_split(usb, pipe)) {
- if (transaction->stage ==
- CVMX_USB_STAGE_NON_CONTROL)
- transaction->stage =
- CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
- else {
- if (buffer_space_left &&
- (bytes_in_last_packet ==
- pipe->max_packet))
- transaction->stage =
- CVMX_USB_STAGE_NON_CONTROL;
- else {
- if (transaction->type ==
- CVMX_USB_TRANSFER_INTERRUPT)
- pipe->next_tx_frame +=
- pipe->interval;
- cvmx_usb_perform_complete(
- usb,
- pipe,
- transaction,
- CVMX_USB_COMPLETE_SUCCESS);
- }
- }
- } else {
- if ((pipe->device_speed ==
- CVMX_USB_SPEED_HIGH) &&
- (pipe->transfer_type ==
- CVMX_USB_TRANSFER_BULK) &&
- (pipe->transfer_dir ==
- CVMX_USB_DIRECTION_OUT) &&
- (usbc_hcint.s.nak))
- pipe->flags |=
- CVMX_USB_PIPE_FLAGS_NEED_PING;
- if (!buffer_space_left ||
- (bytes_in_last_packet <
- pipe->max_packet)) {
- if (transaction->type ==
- CVMX_USB_TRANSFER_INTERRUPT)
- pipe->next_tx_frame +=
- pipe->interval;
- cvmx_usb_perform_complete(usb, pipe,
- transaction,
- CVMX_USB_COMPLETE_SUCCESS);
- }
- }
+ cvmx_usb_transfer_intr(usb, pipe, transaction,
+ buffer_space_left,
+ bytes_in_last_packet);
break;
case CVMX_USB_TRANSFER_ISOCHRONOUS:
- if (cvmx_usb_pipe_needs_split(usb, pipe)) {
- /*
- * ISOCHRONOUS OUT splits don't require a
- * complete split stage. Instead they use a
- * sequence of begin OUT splits to transfer the
- * data 188 bytes at a time. Once the transfer
- * is complete, the pipe sleeps until the next
- * schedule interval
- */
- if (pipe->transfer_dir ==
- CVMX_USB_DIRECTION_OUT) {
- /*
- * If no space left or this wasn't a max
- * size packet then this transfer is
- * complete. Otherwise start it again to
- * send the next 188 bytes
- */
- if (!buffer_space_left ||
- (bytes_this_transfer < 188)) {
- pipe->next_tx_frame +=
- pipe->interval;
- cvmx_usb_perform_complete(usb,
- pipe, transaction,
- CVMX_USB_COMPLETE_SUCCESS);
- }
- } else {
- if (transaction->stage ==
- CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE) {
- /*
- * We are in the incoming data
- * phase. Keep getting data
- * until we run out of space or
- * get a small packet
- */
- if ((buffer_space_left == 0) ||
- (bytes_in_last_packet <
- pipe->max_packet)) {
- pipe->next_tx_frame +=
- pipe->interval;
- cvmx_usb_perform_complete(
- usb,
- pipe,
- transaction,
- CVMX_USB_COMPLETE_SUCCESS);
- }
- } else
- transaction->stage =
- CVMX_USB_STAGE_NON_CONTROL_SPLIT_COMPLETE;
- }
- } else {
- pipe->next_tx_frame += pipe->interval;
- cvmx_usb_perform_complete(usb, pipe,
- transaction,
- CVMX_USB_COMPLETE_SUCCESS);
- }
+ cvmx_usb_transfer_isoc(usb, pipe, transaction,
+ buffer_space_left,
+ bytes_in_last_packet,
+ bytes_this_transfer);
break;
}
} else if (usbc_hcint.s.nak) {
@@ -2946,20 +2909,18 @@ static int cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
* We get channel halted interrupts with no result bits
* sets when the cable is unplugged
*/
- cvmx_usb_perform_complete(usb, pipe, transaction,
- CVMX_USB_COMPLETE_ERROR);
+ cvmx_usb_complete(usb, pipe, transaction,
+ CVMX_USB_STATUS_ERROR);
}
}
return 0;
}
-static void octeon_usb_port_callback(struct cvmx_usb_state *usb)
+static void octeon_usb_port_callback(struct octeon_hcd *usb)
{
- struct octeon_hcd *priv = cvmx_usb_to_octeon(usb);
-
- spin_unlock(&priv->lock);
- usb_hcd_poll_rh_status(octeon_to_hcd(priv));
- spin_lock(&priv->lock);
+ spin_unlock(&usb->lock);
+ usb_hcd_poll_rh_status(octeon_to_hcd(usb));
+ spin_lock(&usb->lock);
}
/**
@@ -2972,7 +2933,7 @@ static void octeon_usb_port_callback(struct cvmx_usb_state *usb)
*
* Returns: 0 or a negative error code.
*/
-static int cvmx_usb_poll(struct cvmx_usb_state *usb)
+static int cvmx_usb_poll(struct octeon_hcd *usb)
{
union cvmx_usbcx_hfnum usbc_hfnum;
union cvmx_usbcx_gintsts usbc_gintsts;
@@ -2981,7 +2942,7 @@ static int cvmx_usb_poll(struct cvmx_usb_state *usb)
/* Update the frame counter */
usbc_hfnum.u32 = cvmx_usb_read_csr32(usb, CVMX_USBCX_HFNUM(usb->index));
- if ((usb->frame_number&0x3fff) > usbc_hfnum.s.frnum)
+ if ((usb->frame_number & 0x3fff) > usbc_hfnum.s.frnum)
usb->frame_number += 0x4000;
usb->frame_number &= ~0x3fffull;
usb->frame_number |= usbc_hfnum.s.frnum;
@@ -3028,8 +2989,8 @@ static int cvmx_usb_poll(struct cvmx_usb_state *usb)
*/
octeon_usb_port_callback(usb);
/* Clear the port change bits */
- usbc_hprt.u32 = cvmx_usb_read_csr32(usb,
- CVMX_USBCX_HPRT(usb->index));
+ usbc_hprt.u32 =
+ cvmx_usb_read_csr32(usb, CVMX_USBCX_HPRT(usb->index));
usbc_hprt.s.prtena = 0;
cvmx_usb_write_csr32(usb, CVMX_USBCX_HPRT(usb->index),
usbc_hprt.u32);
@@ -3056,7 +3017,7 @@ static int cvmx_usb_poll(struct cvmx_usb_state *usb)
channel = __fls(usbc_haint.u32);
cvmx_usb_poll_channel(usb, channel);
- usbc_haint.u32 ^= 1<<channel;
+ usbc_haint.u32 ^= 1 << channel;
}
}
@@ -3073,12 +3034,12 @@ static inline struct octeon_hcd *hcd_to_octeon(struct usb_hcd *hcd)
static irqreturn_t octeon_usb_irq(struct usb_hcd *hcd)
{
- struct octeon_hcd *priv = hcd_to_octeon(hcd);
+ struct octeon_hcd *usb = hcd_to_octeon(hcd);
unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
- cvmx_usb_poll(&priv->usb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
+ cvmx_usb_poll(usb);
+ spin_unlock_irqrestore(&usb->lock, flags);
return IRQ_HANDLED;
}
@@ -3095,16 +3056,16 @@ static void octeon_usb_stop(struct usb_hcd *hcd)
static int octeon_usb_get_frame_number(struct usb_hcd *hcd)
{
- struct octeon_hcd *priv = hcd_to_octeon(hcd);
+ struct octeon_hcd *usb = hcd_to_octeon(hcd);
- return cvmx_usb_get_frame_number(&priv->usb);
+ return cvmx_usb_get_frame_number(usb);
}
static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
struct urb *urb,
gfp_t mem_flags)
{
- struct octeon_hcd *priv = hcd_to_octeon(hcd);
+ struct octeon_hcd *usb = hcd_to_octeon(hcd);
struct device *dev = hcd->self.controller;
struct cvmx_usb_transaction *transaction = NULL;
struct cvmx_usb_pipe *pipe;
@@ -3114,11 +3075,11 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
int rc;
urb->status = 0;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
rc = usb_hcd_link_urb_to_ep(hcd, urb);
if (rc) {
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&usb->lock, flags);
return rc;
}
@@ -3184,7 +3145,7 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
dev = dev->parent;
}
}
- pipe = cvmx_usb_open_pipe(&priv->usb, usb_pipedevice(urb->pipe),
+ pipe = cvmx_usb_open_pipe(usb, usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe), speed,
le16_to_cpu(ep->desc.wMaxPacketSize)
& 0x7ff,
@@ -3198,7 +3159,7 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
split_device, split_port);
if (!pipe) {
usb_hcd_unlink_urb_from_ep(hcd, urb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&usb->lock, flags);
dev_dbg(dev, "Failed to create pipe\n");
return -ENOMEM;
}
@@ -3227,8 +3188,7 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
urb->iso_frame_desc[i].offset;
iso_packet[i].length =
urb->iso_frame_desc[i].length;
- iso_packet[i].status =
- CVMX_USB_COMPLETE_ERROR;
+ iso_packet[i].status = CVMX_USB_STATUS_ERROR;
}
/*
* Store a pointer to the list in the URB setup_packet
@@ -3236,7 +3196,7 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
* this saves us a bunch of logic.
*/
urb->setup_packet = (char *)iso_packet;
- transaction = cvmx_usb_submit_isochronous(&priv->usb,
+ transaction = cvmx_usb_submit_isochronous(usb,
pipe, urb);
/*
* If submit failed we need to free our private packet
@@ -3252,29 +3212,29 @@ static int octeon_usb_urb_enqueue(struct usb_hcd *hcd,
dev_dbg(dev, "Submit interrupt to %d.%d\n",
usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe));
- transaction = cvmx_usb_submit_interrupt(&priv->usb, pipe, urb);
+ transaction = cvmx_usb_submit_interrupt(usb, pipe, urb);
break;
case PIPE_CONTROL:
dev_dbg(dev, "Submit control to %d.%d\n",
usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe));
- transaction = cvmx_usb_submit_control(&priv->usb, pipe, urb);
+ transaction = cvmx_usb_submit_control(usb, pipe, urb);
break;
case PIPE_BULK:
dev_dbg(dev, "Submit bulk to %d.%d\n",
usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe));
- transaction = cvmx_usb_submit_bulk(&priv->usb, pipe, urb);
+ transaction = cvmx_usb_submit_bulk(usb, pipe, urb);
break;
}
if (!transaction) {
usb_hcd_unlink_urb_from_ep(hcd, urb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&usb->lock, flags);
dev_dbg(dev, "Failed to submit\n");
return -ENOMEM;
}
urb->hcpriv = transaction;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&usb->lock, flags);
return 0;
}
@@ -3282,24 +3242,24 @@ static int octeon_usb_urb_dequeue(struct usb_hcd *hcd,
struct urb *urb,
int status)
{
- struct octeon_hcd *priv = hcd_to_octeon(hcd);
+ struct octeon_hcd *usb = hcd_to_octeon(hcd);
unsigned long flags;
int rc;
if (!urb->dev)
return -EINVAL;
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc)
goto out;
urb->status = status;
- cvmx_usb_cancel(&priv->usb, urb->ep->hcpriv, urb->hcpriv);
+ cvmx_usb_cancel(usb, urb->ep->hcpriv, urb->hcpriv);
out:
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&usb->lock, flags);
return rc;
}
@@ -3310,28 +3270,28 @@ static void octeon_usb_endpoint_disable(struct usb_hcd *hcd,
struct device *dev = hcd->self.controller;
if (ep->hcpriv) {
- struct octeon_hcd *priv = hcd_to_octeon(hcd);
+ struct octeon_hcd *usb = 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))
+ spin_lock_irqsave(&usb->lock, flags);
+ cvmx_usb_cancel_all(usb, pipe);
+ if (cvmx_usb_close_pipe(usb, pipe))
dev_dbg(dev, "Closing pipe %p failed\n", pipe);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&usb->lock, flags);
ep->hcpriv = NULL;
}
}
static int octeon_usb_hub_status_data(struct usb_hcd *hcd, char *buf)
{
- struct octeon_hcd *priv = hcd_to_octeon(hcd);
+ struct octeon_hcd *usb = hcd_to_octeon(hcd);
struct cvmx_usb_port_status port_status;
unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
- port_status = cvmx_usb_get_status(&priv->usb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
+ port_status = cvmx_usb_get_status(usb);
+ spin_unlock_irqrestore(&usb->lock, flags);
buf[0] = 0;
buf[0] = port_status.connect_change << 1;
@@ -3339,12 +3299,11 @@ static int octeon_usb_hub_status_data(struct usb_hcd *hcd, char *buf)
}
static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
- u16 wIndex, char *buf, u16 wLength)
+ u16 wIndex, char *buf, u16 wLength)
{
- struct octeon_hcd *priv = hcd_to_octeon(hcd);
+ struct octeon_hcd *usb = hcd_to_octeon(hcd);
struct device *dev = hcd->self.controller;
struct cvmx_usb_port_status usb_port_status;
- struct cvmx_usb_state *usb = &priv->usb;
int port_status;
struct usb_hub_descriptor *desc;
unsigned long flags;
@@ -3371,9 +3330,9 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
dev_dbg(dev, " ENABLE\n");
- spin_lock_irqsave(&priv->lock, flags);
- cvmx_usb_disable(&priv->usb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
+ cvmx_usb_disable(usb);
+ spin_unlock_irqrestore(&usb->lock, flags);
break;
case USB_PORT_FEAT_SUSPEND:
dev_dbg(dev, " SUSPEND\n");
@@ -3390,20 +3349,18 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_C_CONNECTION:
dev_dbg(dev, " C_CONNECTION\n");
/* Clears drivers internal connect status change flag */
- spin_lock_irqsave(&priv->lock, flags);
- priv->usb.port_status =
- cvmx_usb_get_status(&priv->usb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
+ usb->port_status = cvmx_usb_get_status(usb);
+ spin_unlock_irqrestore(&usb->lock, flags);
break;
case USB_PORT_FEAT_C_RESET:
dev_dbg(dev, " C_RESET\n");
/*
* Clears the driver's internal Port Reset Change flag.
*/
- spin_lock_irqsave(&priv->lock, flags);
- priv->usb.port_status =
- cvmx_usb_get_status(&priv->usb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
+ usb->port_status = cvmx_usb_get_status(usb);
+ spin_unlock_irqrestore(&usb->lock, flags);
break;
case USB_PORT_FEAT_C_ENABLE:
dev_dbg(dev, " C_ENABLE\n");
@@ -3411,10 +3368,9 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
* Clears the driver's internal Port Enable/Disable
* Change flag.
*/
- spin_lock_irqsave(&priv->lock, flags);
- priv->usb.port_status =
- cvmx_usb_get_status(&priv->usb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
+ usb->port_status = cvmx_usb_get_status(usb);
+ spin_unlock_irqrestore(&usb->lock, flags);
break;
case USB_PORT_FEAT_C_SUSPEND:
dev_dbg(dev, " C_SUSPEND\n");
@@ -3427,10 +3383,9 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case USB_PORT_FEAT_C_OVER_CURRENT:
dev_dbg(dev, " C_OVER_CURRENT\n");
/* Clears the driver's overcurrent Change flag */
- spin_lock_irqsave(&priv->lock, flags);
- priv->usb.port_status =
- cvmx_usb_get_status(&priv->usb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
+ usb->port_status = cvmx_usb_get_status(usb);
+ spin_unlock_irqrestore(&usb->lock, flags);
break;
default:
dev_dbg(dev, " UNKNOWN\n");
@@ -3451,7 +3406,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
break;
case GetHubStatus:
dev_dbg(dev, "GetHubStatus\n");
- *(__le32 *) buf = 0;
+ *(__le32 *)buf = 0;
break;
case GetPortStatus:
dev_dbg(dev, "GetPortStatus\n");
@@ -3460,9 +3415,9 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
return -EINVAL;
}
- spin_lock_irqsave(&priv->lock, flags);
- usb_port_status = cvmx_usb_get_status(&priv->usb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
+ usb_port_status = cvmx_usb_get_status(usb);
+ spin_unlock_irqrestore(&usb->lock, flags);
port_status = 0;
if (usb_port_status.connect_change) {
@@ -3503,7 +3458,7 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
dev_dbg(dev, " LOWSPEED\n");
}
- *((__le32 *) buf) = cpu_to_le32(port_status);
+ *((__le32 *)buf) = cpu_to_le32(port_status);
break;
case SetHubFeature:
dev_dbg(dev, "SetHubFeature\n");
@@ -3525,16 +3480,16 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
/*
* Program the port power bit to drive VBUS on the USB.
*/
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
USB_SET_FIELD32(CVMX_USBCX_HPRT(usb->index),
cvmx_usbcx_hprt, prtpwr, 1);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irqrestore(&usb->lock, flags);
return 0;
case USB_PORT_FEAT_RESET:
dev_dbg(dev, " RESET\n");
- spin_lock_irqsave(&priv->lock, flags);
- cvmx_usb_reset_port(&priv->usb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
+ cvmx_usb_reset_port(usb);
+ spin_unlock_irqrestore(&usb->lock, flags);
return 0;
case USB_PORT_FEAT_INDICATOR:
dev_dbg(dev, " INDICATOR\n");
@@ -3579,23 +3534,26 @@ static int octeon_usb_probe(struct platform_device *pdev)
struct device_node *usbn_node;
int irq = platform_get_irq(pdev, 0);
struct device *dev = &pdev->dev;
- struct octeon_hcd *priv;
+ struct octeon_hcd *usb;
struct usb_hcd *hcd;
u32 clock_rate = 48000000;
bool is_crystal_clock = false;
const char *clock_type;
int i;
- if (dev->of_node == NULL) {
+ if (!dev->of_node) {
dev_err(dev, "Error: empty of_node\n");
return -ENXIO;
}
usbn_node = dev->of_node->parent;
i = of_property_read_u32(usbn_node,
- "refclk-frequency", &clock_rate);
+ "clock-frequency", &clock_rate);
+ if (i)
+ i = of_property_read_u32(usbn_node,
+ "refclk-frequency", &clock_rate);
if (i) {
- dev_err(dev, "No USBN \"refclk-frequency\"\n");
+ dev_err(dev, "No USBN \"clock-frequency\"\n");
return -ENXIO;
}
switch (clock_rate) {
@@ -3609,14 +3567,16 @@ static int octeon_usb_probe(struct platform_device *pdev)
initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ;
break;
default:
- dev_err(dev, "Illebal USBN \"refclk-frequency\" %u\n",
- clock_rate);
+ dev_err(dev, "Illegal USBN \"clock-frequency\" %u\n",
+ clock_rate);
return -ENXIO;
-
}
i = of_property_read_string(usbn_node,
- "refclk-type", &clock_type);
+ "cavium,refclk-type", &clock_type);
+ if (i)
+ i = of_property_read_string(usbn_node,
+ "refclk-type", &clock_type);
if (!i && strcmp("crystal", clock_type) == 0)
is_crystal_clock = true;
@@ -3627,7 +3587,7 @@ static int octeon_usb_probe(struct platform_device *pdev)
initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND;
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res_mem == NULL) {
+ if (!res_mem) {
dev_err(dev, "found no memory resource\n");
return -ENXIO;
}
@@ -3673,31 +3633,31 @@ static int octeon_usb_probe(struct platform_device *pdev)
return -1;
}
hcd->uses_new_polling = 1;
- priv = (struct octeon_hcd *)hcd->hcd_priv;
+ usb = (struct octeon_hcd *)hcd->hcd_priv;
- spin_lock_init(&priv->lock);
+ spin_lock_init(&usb->lock);
- priv->usb.init_flags = initialize_flags;
+ usb->init_flags = initialize_flags;
/* Initialize the USB state structure */
- priv->usb.index = usb_num;
- INIT_LIST_HEAD(&priv->usb.idle_pipes);
- for (i = 0; i < ARRAY_SIZE(priv->usb.active_pipes); i++)
- INIT_LIST_HEAD(&priv->usb.active_pipes[i]);
+ usb->index = usb_num;
+ INIT_LIST_HEAD(&usb->idle_pipes);
+ for (i = 0; i < ARRAY_SIZE(usb->active_pipes); i++)
+ INIT_LIST_HEAD(&usb->active_pipes[i]);
/* Due to an errata, CN31XX doesn't support DMA */
if (OCTEON_IS_MODEL(OCTEON_CN31XX)) {
- priv->usb.init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA;
+ usb->init_flags |= CVMX_USB_INITIALIZE_FLAGS_NO_DMA;
/* Only use one channel with non DMA */
- priv->usb.idle_hardware_channels = 0x1;
+ usb->idle_hardware_channels = 0x1;
} else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
/* CN5XXX have an errata with channel 3 */
- priv->usb.idle_hardware_channels = 0xf7;
+ usb->idle_hardware_channels = 0xf7;
} else {
- priv->usb.idle_hardware_channels = 0xff;
+ usb->idle_hardware_channels = 0xff;
}
- status = cvmx_usb_initialize(dev, &priv->usb);
+ status = cvmx_usb_initialize(dev, usb);
if (status) {
dev_dbg(dev, "USB initialization failed with %d\n", status);
kfree(hcd);
@@ -3722,13 +3682,13 @@ static int octeon_usb_remove(struct platform_device *pdev)
int status;
struct device *dev = &pdev->dev;
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct octeon_hcd *priv = hcd_to_octeon(hcd);
+ struct octeon_hcd *usb = hcd_to_octeon(hcd);
unsigned long flags;
usb_remove_hcd(hcd);
- spin_lock_irqsave(&priv->lock, flags);
- status = cvmx_usb_shutdown(&priv->usb);
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_lock_irqsave(&usb->lock, flags);
+ status = cvmx_usb_shutdown(usb);
+ spin_unlock_irqrestore(&usb->lock, flags);
if (status)
dev_dbg(dev, "USB shutdown failed with %d\n", status);
@@ -3747,7 +3707,7 @@ MODULE_DEVICE_TABLE(of, octeon_usb_match);
static struct platform_driver octeon_usb_driver = {
.driver = {
- .name = "OcteonUSB",
+ .name = "octeon-hcd",
.of_match_table = octeon_usb_match,
},
.probe = octeon_usb_probe,