#include <asm/octeon/cvmx-sysinfo.h>
#include <asm/octeon/cvmx-helper-board.h>
-#include "cvmx-usbcx-defs.h"
-#include "cvmx-usbnx-defs.h"
+#include "octeon-hcd.h"
/**
* enum cvmx_usb_speed - the possible USB device speeds
/**
* enum cvmx_usb_pipe_flags - internal flags for a pipe.
*
- * @__CVMX_USB_PIPE_FLAGS_OPEN: Used internally to determine if a pipe is
- * open. Do not use.
* @__CVMX_USB_PIPE_FLAGS_SCHEDULED: Used internally to determine if a pipe is
* actively using hardware. Do not use.
* @__CVMX_USB_PIPE_FLAGS_NEED_PING: Used internally to determine if a high
* use.
*/
enum cvmx_usb_pipe_flags {
- __CVMX_USB_PIPE_FLAGS_OPEN = 1 << 16,
__CVMX_USB_PIPE_FLAGS_SCHEDULED = 1 << 17,
__CVMX_USB_PIPE_FLAGS_NEED_PING = 1 << 18,
};
/* Maximum number of times to retry failed transactions */
#define MAX_RETRIES 3
-/* Maximum number of pipes that can be open at once */
-#define MAX_PIPES 32
-
-/* Maximum number of outstanding transactions across all pipes */
-#define MAX_TRANSACTIONS 256
-
/* Maximum number of hardware channels supported by the USB block */
#define MAX_CHANNELS 8
*/
#define MAX_TRANSFER_PACKETS ((1<<10)-1)
-enum cvmx_usb_transaction_flags {
- __CVMX_USB_TRANSACTION_FLAGS_IN_USE = 1<<16,
-};
-
enum {
USB_CLOCK_TYPE_REF_12,
USB_CLOCK_TYPE_REF_24,
struct cvmx_usb_transaction *prev;
struct cvmx_usb_transaction *next;
enum cvmx_usb_transfer type;
- enum cvmx_usb_transaction_flags flags;
uint64_t buffer;
int buffer_length;
uint64_t control_header;
* usbcx_hprt: Stored port status so we don't need to read a CSR to
* determine splits.
* pipe_for_channel: Map channels to pipes.
- * free_transaction_head: List of free transactions head.
- * free_transaction_tail: List of free transactions tail.
* pipe: Storage for pipes.
- * transaction: Storage for transactions.
* indent: Used by debug output to indent functions.
* port_status: Last port status used for change notification.
- * free_pipes: List of all pipes that are currently closed.
* idle_pipes: List of open pipes that have no transactions.
* active_pipes: Active pipes indexed by transfer type.
* frame_number: Increments every SOF interrupt for time keeping.
int idle_hardware_channels;
union cvmx_usbcx_hprt usbcx_hprt;
struct cvmx_usb_pipe *pipe_for_channel[MAX_CHANNELS];
- struct cvmx_usb_transaction *free_transaction_head;
- struct cvmx_usb_transaction *free_transaction_tail;
- struct cvmx_usb_pipe pipe[MAX_PIPES];
- struct cvmx_usb_transaction transaction[MAX_TRANSACTIONS];
int indent;
struct cvmx_usb_port_status port_status;
- struct cvmx_usb_pipe_list free_pipes;
struct cvmx_usb_pipe_list idle_pipes;
struct cvmx_usb_pipe_list active_pipes[4];
uint64_t frame_number;
static inline int __cvmx_usb_pipe_needs_split(struct cvmx_usb_state *usb,
struct cvmx_usb_pipe *pipe)
{
- return ((pipe->device_speed != CVMX_USB_SPEED_HIGH) && (usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH));
+ return pipe->device_speed != CVMX_USB_SPEED_HIGH &&
+ usb->usbcx_hprt.s.prtspd == CVMX_USB_SPEED_HIGH;
}
return arch_ports;
}
-
-/**
- * Allocate a usb transaction for use
- *
- * @usb: USB device state populated by
- * cvmx_usb_initialize().
- *
- * Returns: Transaction or NULL
- */
-static inline struct cvmx_usb_transaction *__cvmx_usb_alloc_transaction(struct cvmx_usb_state *usb)
-{
- struct cvmx_usb_transaction *t;
- t = usb->free_transaction_head;
- if (t) {
- usb->free_transaction_head = t->next;
- if (!usb->free_transaction_head)
- usb->free_transaction_tail = NULL;
- }
- if (t) {
- memset(t, 0, sizeof(*t));
- t->flags = __CVMX_USB_TRANSACTION_FLAGS_IN_USE;
- }
- return t;
-}
-
-
-/**
- * Free a usb transaction
- *
- * @usb: USB device state populated by
- * cvmx_usb_initialize().
- * @transaction:
- * Transaction to free
- */
-static inline void __cvmx_usb_free_transaction(struct cvmx_usb_state *usb,
- struct cvmx_usb_transaction *transaction)
-{
- transaction->flags = 0;
- transaction->prev = NULL;
- transaction->next = NULL;
- if (usb->free_transaction_tail)
- usb->free_transaction_tail->next = transaction;
- else
- usb->free_transaction_head = transaction;
- usb->free_transaction_tail = transaction;
-}
-
-
/**
* Add a pipe to the tail of a list
* @list: List to add pipe to
usb->init_flags = flags;
/* Initialize the USB state structure */
- {
- int i;
- usb->index = usb_port_number;
-
- /* Initialize the transaction double linked list */
- usb->free_transaction_head = NULL;
- usb->free_transaction_tail = NULL;
- for (i = 0; i < MAX_TRANSACTIONS; i++)
- __cvmx_usb_free_transaction(usb, usb->transaction + i);
- for (i = 0; i < MAX_PIPES; i++)
- __cvmx_usb_append_pipe(&usb->free_pipes, usb->pipe + i);
- }
+ usb->index = usb_port_number;
/*
* Power On Reset and PHY Initialization
* source at USB_XO. USB_XI should be tied to GND.
* Most Octeon evaluation boards require this setting
*/
- if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
- /* From CN31XX,CN30XX manual */
- usbn_clk_ctl.cn31xx.p_rclk = 1;
- usbn_clk_ctl.cn31xx.p_xenbn = 0;
- } else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
- /* From CN56XX,CN50XX manual */
- usbn_clk_ctl.cn56xx.p_rtype = 2;
+ if (OCTEON_IS_MODEL(OCTEON_CN3XXX) ||
+ OCTEON_IS_MODEL(OCTEON_CN56XX) ||
+ OCTEON_IS_MODEL(OCTEON_CN50XX))
+ /* From CN56XX,CN50XX,CN31XX,CN30XX manuals */
+ usbn_clk_ctl.s.p_rtype = 2; /* p_rclk=1 & p_xenbn=0 */
else
/* From CN52XX manual */
- usbn_clk_ctl.cn52xx.p_rtype = 1;
+ usbn_clk_ctl.s.p_rtype = 1;
switch (flags & CVMX_USB_INITIALIZE_FLAGS_CLOCK_MHZ_MASK) {
case CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ:
* The USB port uses a 12MHz crystal as clock source
* at USB_XO and USB_XI
*/
- if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
+ if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
/* From CN31XX,CN30XX manual */
- usbn_clk_ctl.cn31xx.p_rclk = 1;
- usbn_clk_ctl.cn31xx.p_xenbn = 1;
- } else if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN50XX))
- /* From CN56XX,CN50XX manual */
- usbn_clk_ctl.cn56xx.p_rtype = 0;
+ usbn_clk_ctl.s.p_rtype = 3; /* p_rclk=1 & p_xenbn=1 */
else
- /* From CN52XX manual */
- usbn_clk_ctl.cn52xx.p_rtype = 0;
+ /* From CN56XX,CN52XX,CN50XX manuals. */
+ usbn_clk_ctl.s.p_rtype = 0;
usbn_clk_ctl.s.p_c_sel = 0;
}
return result;
}
-/**
- * Convert a USB transaction into a handle
- *
- * @usb: USB device state populated by cvmx_usb_initialize().
- * @transaction:
- * Transaction to get handle for
- *
- * Returns: Handle
- */
-static inline int __cvmx_usb_get_submit_handle(struct cvmx_usb_state *usb,
- struct cvmx_usb_transaction *transaction)
-{
- return ((unsigned long)transaction - (unsigned long)usb->transaction) /
- sizeof(*transaction);
-}
-
-
-/**
- * Convert a USB pipe into a handle
- *
- * @usb: USB device state populated by cvmx_usb_initialize().
- * @pipe: Pipe to get handle for
- *
- * Returns: Handle
- */
-static inline int __cvmx_usb_get_pipe_handle(struct cvmx_usb_state *usb,
- struct cvmx_usb_pipe *pipe)
-{
- return ((unsigned long)pipe - (unsigned long)usb->pipe) / sizeof(*pipe);
-}
-
-
/**
* Open a virtual pipe between the host and a USB device. A pipe
* must be opened before data can be transferred between a device
* this is only used for full/low speed
* devices behind a high speed hub.
*
- * Returns: A non negative value is a pipe handle. Negative
- * values are error codes.
+ * Returns: A non-NULL value is a pipe. NULL means an error.
*/
-static int cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
- int device_addr, int endpoint_num,
- enum cvmx_usb_speed device_speed, int max_packet,
- enum cvmx_usb_transfer transfer_type,
- enum cvmx_usb_direction transfer_dir,
- int interval, int multi_count,
- int hub_device_addr, int hub_port)
+static struct cvmx_usb_pipe *cvmx_usb_open_pipe(struct cvmx_usb_state *usb,
+ int device_addr, int
+ endpoint_num,
+ enum cvmx_usb_speed
+ device_speed,
+ int max_packet,
+ enum cvmx_usb_transfer
+ transfer_type,
+ enum cvmx_usb_direction
+ transfer_dir,
+ int interval, int multi_count,
+ int hub_device_addr,
+ int hub_port)
{
struct cvmx_usb_pipe *pipe;
if (unlikely((device_addr < 0) || (device_addr > MAX_USB_ADDRESS)))
- return -EINVAL;
+ return NULL;
if (unlikely((endpoint_num < 0) || (endpoint_num > MAX_USB_ENDPOINT)))
- return -EINVAL;
+ return NULL;
if (unlikely(device_speed > CVMX_USB_SPEED_LOW))
- return -EINVAL;
+ return NULL;
if (unlikely((max_packet <= 0) || (max_packet > 1024)))
- return -EINVAL;
+ return NULL;
if (unlikely(transfer_type > CVMX_USB_TRANSFER_INTERRUPT))
- return -EINVAL;
+ return NULL;
if (unlikely((transfer_dir != CVMX_USB_DIRECTION_OUT) &&
(transfer_dir != CVMX_USB_DIRECTION_IN)))
- return -EINVAL;
+ return NULL;
if (unlikely(interval < 0))
- return -EINVAL;
+ return NULL;
if (unlikely((transfer_type == CVMX_USB_TRANSFER_CONTROL) && interval))
- return -EINVAL;
+ return NULL;
if (unlikely(multi_count < 0))
- return -EINVAL;
+ return NULL;
if (unlikely((device_speed != CVMX_USB_SPEED_HIGH) &&
(multi_count != 0)))
- return -EINVAL;
+ return NULL;
if (unlikely((hub_device_addr < 0) || (hub_device_addr > MAX_USB_ADDRESS)))
- return -EINVAL;
+ return NULL;
if (unlikely((hub_port < 0) || (hub_port > MAX_USB_HUB_PORT)))
- return -EINVAL;
+ return NULL;
- /* Find a free pipe */
- pipe = usb->free_pipes.head;
+ pipe = kzalloc(sizeof(*pipe), GFP_ATOMIC);
if (!pipe)
- return -ENOMEM;
- __cvmx_usb_remove_pipe(&usb->free_pipes, pipe);
- pipe->flags = __CVMX_USB_PIPE_FLAGS_OPEN;
+ return NULL;
if ((device_speed == CVMX_USB_SPEED_HIGH) &&
(transfer_dir == CVMX_USB_DIRECTION_OUT) &&
(transfer_type == CVMX_USB_TRANSFER_BULK))
* it doesn't have any submitted requests
*/
- return __cvmx_usb_get_pipe_handle(usb, pipe);
+ return pipe;
}
static void octeon_usb_urb_complete_callback(struct cvmx_usb_state *usb,
enum cvmx_usb_complete status,
- int pipe_handle,
- int submit_handle,
+ struct cvmx_usb_pipe *pipe,
+ struct cvmx_usb_transaction
+ *transaction,
int bytes_transferred,
struct urb *urb)
{
urb->actual_length = bytes_transferred;
urb->hcpriv = NULL;
- if (!list_empty(&urb->urb_list)) {
+ if (!list_empty(&urb->urb_list))
/*
* It is on the dequeue_list, but we are going to call
* usb_hcd_giveback_urb(), so we must clear it from
* the list. We got to it before the
* octeon_usb_urb_dequeue_work() tasklet did.
*/
- list_del(&urb->urb_list);
- /* No longer on the dequeue_list. */
- INIT_LIST_HEAD(&urb->urb_list);
- }
+ list_del_init(&urb->urb_list);
/* For Isochronous transactions we need to update the URB packet status
list from data in our private copy */
urb->iso_frame_desc[i].actual_length = iso_packet[i].length;
urb->actual_length += urb->iso_frame_desc[i].actual_length;
} else {
- dev_dbg(dev, "ISOCHRONOUS packet=%d of %d status=%d pipe=%d submit=%d size=%d\n",
+ dev_dbg(dev, "ISOCHRONOUS packet=%d of %d status=%d pipe=%p transaction=%p size=%d\n",
i, urb->number_of_packets,
- iso_packet[i].status, pipe_handle,
- submit_handle, iso_packet[i].length);
+ iso_packet[i].status, pipe,
+ transaction, iso_packet[i].length);
urb->iso_frame_desc[i].status = -EREMOTEIO;
}
}
urb->status = -ENOENT;
break;
case CVMX_USB_COMPLETE_STALL:
- dev_dbg(dev, "status=stall pipe=%d submit=%d size=%d\n",
- pipe_handle, submit_handle, bytes_transferred);
+ 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:
- dev_dbg(dev, "status=babble pipe=%d submit=%d size=%d\n",
- pipe_handle, submit_handle, bytes_transferred);
+ 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:
- dev_dbg(dev, "status=short pipe=%d submit=%d size=%d\n",
- pipe_handle, submit_handle, bytes_transferred);
+ 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:
- dev_dbg(dev, "status=%d pipe=%d submit=%d size=%d\n",
- status, pipe_handle, submit_handle, bytes_transferred);
+ dev_dbg(dev, "status=%d pipe=%p transaction=%p size=%d\n",
+ status, pipe, transaction, bytes_transferred);
urb->status = -EPROTO;
break;
}
struct cvmx_usb_transaction *transaction,
enum cvmx_usb_complete complete_code)
{
- int pipe_handle;
- int submit_handle;
-
/* If this was a split then clear our split in progress marker */
if (usb->active_split == transaction)
usb->active_split = NULL;
__cvmx_usb_append_pipe(&usb->idle_pipes, pipe);
}
- pipe_handle = __cvmx_usb_get_pipe_handle(usb, pipe);
- submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
- octeon_usb_urb_complete_callback(usb, complete_code, pipe_handle,
- submit_handle,
+ octeon_usb_urb_complete_callback(usb, complete_code, pipe,
+ transaction,
transaction->actual_bytes,
transaction->urb);
- __cvmx_usb_free_transaction(usb, transaction);
+ kfree(transaction);
done:
return;
}
* of transactions.
*
* @usb:
- * @pipe_handle:
- * Which pipe to submit to. Will be validated in this function.
+ * @pipe: Which pipe to submit to.
* @type: Transaction type
* @buffer: User buffer for the transaction
* @buffer_length:
* A description of each ISO packet
* @urb: URB for the callback
*
- * Returns: Submit handle or negative on failure. Matches the result
- * in the external API.
+ * Returns: Transaction or NULL on failure.
*/
-static int __cvmx_usb_submit_transaction(struct cvmx_usb_state *usb,
- int pipe_handle,
- enum cvmx_usb_transfer type,
- uint64_t buffer,
- int buffer_length,
- uint64_t control_header,
- int iso_start_frame,
- int iso_number_packets,
- struct cvmx_usb_iso_packet *iso_packets,
- struct urb *urb)
+static struct cvmx_usb_transaction *__cvmx_usb_submit_transaction(struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ enum cvmx_usb_transfer type,
+ uint64_t buffer,
+ int buffer_length,
+ uint64_t control_header,
+ int iso_start_frame,
+ int iso_number_packets,
+ struct cvmx_usb_iso_packet *iso_packets,
+ struct urb *urb)
{
- int submit_handle;
struct cvmx_usb_transaction *transaction;
- struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
- if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
- return -EINVAL;
- /* Fail if the pipe isn't open */
- if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
- return -EINVAL;
if (unlikely(pipe->transfer_type != type))
- return -EINVAL;
+ return NULL;
- transaction = __cvmx_usb_alloc_transaction(usb);
+ transaction = kzalloc(sizeof(*transaction), GFP_ATOMIC);
if (unlikely(!transaction))
- return -ENOMEM;
+ return NULL;
transaction->type = type;
transaction->buffer = buffer;
}
pipe->tail = transaction;
- submit_handle = __cvmx_usb_get_submit_handle(usb, transaction);
-
/* We may need to schedule the pipe if this was the head of the pipe */
if (!transaction->prev)
__cvmx_usb_schedule(usb, 0);
- return submit_handle;
+ return transaction;
}
* Call to submit a USB Bulk transfer to a pipe.
*
* @usb: USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- * Handle to the pipe for the transfer.
+ * @pipe: Handle to the pipe for the transfer.
* @urb: URB.
*
- * Returns: A submitted transaction handle or negative on
- * failure. Negative values are error codes.
+ * Returns: A submitted transaction or NULL on failure.
*/
-static int cvmx_usb_submit_bulk(struct cvmx_usb_state *usb, int pipe_handle,
- struct urb *urb)
+static struct cvmx_usb_transaction *cvmx_usb_submit_bulk(struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct urb *urb)
{
- int submit_handle;
-
- submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
- CVMX_USB_TRANSFER_BULK,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- 0, /* control_header */
- 0, /* iso_start_frame */
- 0, /* iso_number_packets */
- NULL, /* iso_packets */
- urb);
- return submit_handle;
+ return __cvmx_usb_submit_transaction(usb, pipe, CVMX_USB_TRANSFER_BULK,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ 0, /* control_header */
+ 0, /* iso_start_frame */
+ 0, /* iso_number_packets */
+ NULL, /* iso_packets */
+ urb);
}
* Call to submit a USB Interrupt transfer to a pipe.
*
* @usb: USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- * Handle to the pipe for the transfer.
- * @buffer: Physical address of the data buffer in
- * memory. Note that this is NOT A POINTER, but
- * the full 64bit physical address of the
- * buffer. This may be zero if buffer_length is
- * zero.
- * @buffer_length:
- * Length of buffer in bytes.
+ * @pipe: Handle to the pipe for the transfer.
* @urb: URB returned when the callback is called.
*
- * Returns: A submitted transaction handle or negative on
- * failure. Negative values are error codes.
+ * Returns: A submitted transaction or NULL on failure.
*/
-static int cvmx_usb_submit_interrupt(struct cvmx_usb_state *usb,
- int pipe_handle, uint64_t buffer,
- int buffer_length, struct urb *urb)
+static struct cvmx_usb_transaction *cvmx_usb_submit_interrupt(struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct urb *urb)
{
- int submit_handle;
-
- /* Pipe handle checking is done later in a common place */
- if (unlikely(!buffer))
- return -EINVAL;
- if (unlikely(buffer_length < 0))
- return -EINVAL;
-
- submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
- CVMX_USB_TRANSFER_INTERRUPT,
- buffer,
- buffer_length,
- 0, /* control_header */
- 0, /* iso_start_frame */
- 0, /* iso_number_packets */
- NULL, /* iso_packets */
- urb);
- return submit_handle;
+ return __cvmx_usb_submit_transaction(usb, pipe,
+ CVMX_USB_TRANSFER_INTERRUPT,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ 0, /* control_header */
+ 0, /* iso_start_frame */
+ 0, /* iso_number_packets */
+ NULL, /* iso_packets */
+ urb);
}
* Call to submit a USB Control transfer to a pipe.
*
* @usb: USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- * Handle to the pipe for the transfer.
+ * @pipe: Handle to the pipe for the transfer.
* @urb: URB.
*
- * Returns: A submitted transaction handle or negative on
- * failure. Negative values are error codes.
+ * Returns: A submitted transaction or NULL on failure.
*/
-static int cvmx_usb_submit_control(struct cvmx_usb_state *usb, int pipe_handle,
- struct urb *urb)
+static struct cvmx_usb_transaction *cvmx_usb_submit_control(struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct urb *urb)
{
- int submit_handle;
int buffer_length = urb->transfer_buffer_length;
uint64_t control_header = urb->setup_dma;
union cvmx_usb_control_header *header =
cvmx_phys_to_ptr(control_header);
- /* Pipe handle checking is done later in a common place */
if ((header->s.request_type & 0x80) == 0)
buffer_length = le16_to_cpu(header->s.length);
- submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
- CVMX_USB_TRANSFER_CONTROL,
- urb->transfer_dma,
- buffer_length,
- control_header,
- 0, /* iso_start_frame */
- 0, /* iso_number_packets */
- NULL, /* iso_packets */
- urb);
- return submit_handle;
+ return __cvmx_usb_submit_transaction(usb, pipe,
+ CVMX_USB_TRANSFER_CONTROL,
+ urb->transfer_dma, buffer_length,
+ control_header,
+ 0, /* iso_start_frame */
+ 0, /* iso_number_packets */
+ NULL, /* iso_packets */
+ urb);
}
* Call to submit a USB Isochronous transfer to a pipe.
*
* @usb: USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- * Handle to the pipe for the transfer.
- * @start_frame:
- * Number of frames into the future to schedule
- * this transaction.
- * @number_packets:
- * Number of sequential packets to transfer.
- * "packets" is a pointer to an array of this
- * many packet structures.
- * @packets: Description of each transfer packet as
- * defined by struct cvmx_usb_iso_packet. The array
- * pointed to here must stay valid until the
- * complete callback is called.
- * @buffer: Physical address of the data buffer in
- * memory. Note that this is NOT A POINTER, but
- * the full 64bit physical address of the
- * buffer. This may be zero if buffer_length is
- * zero.
- * @buffer_length:
- * Length of buffer in bytes.
+ * @pipe: Handle to the pipe for the transfer.
* @urb: URB returned when the callback is called.
*
- * Returns: A submitted transaction handle or negative on
- * failure. Negative values are error codes.
+ * Returns: A submitted transaction or NULL on failure.
*/
-static int cvmx_usb_submit_isochronous(struct cvmx_usb_state *usb,
- int pipe_handle, int start_frame,
- int number_packets, struct
- cvmx_usb_iso_packet packets[],
- uint64_t buffer, int buffer_length,
- struct urb *urb)
+static struct cvmx_usb_transaction *cvmx_usb_submit_isochronous(struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct urb *urb)
{
- int submit_handle;
-
- /* Pipe handle checking is done later in a common place */
- if (unlikely(start_frame < 0))
- return -EINVAL;
- if (unlikely(number_packets < 1))
- return -EINVAL;
- if (unlikely(!packets))
- return -EINVAL;
- if (unlikely(!buffer))
- return -EINVAL;
- if (unlikely(buffer_length < 0))
- return -EINVAL;
-
- submit_handle = __cvmx_usb_submit_transaction(usb, pipe_handle,
- CVMX_USB_TRANSFER_ISOCHRONOUS,
- buffer,
- buffer_length,
- 0, /* control_header */
- start_frame,
- number_packets,
- packets,
- urb);
- return submit_handle;
+ struct cvmx_usb_iso_packet *packets;
+
+ packets = (struct cvmx_usb_iso_packet *) urb->setup_packet;
+ return __cvmx_usb_submit_transaction(usb, pipe,
+ CVMX_USB_TRANSFER_ISOCHRONOUS,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ 0, /* control_header */
+ urb->start_frame,
+ urb->number_of_packets,
+ packets, urb);
}
* associated callback.
*
* @usb: USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- * Pipe handle to cancel requests in.
- * @submit_handle:
- * Handle to transaction to cancel, returned by the submit
- * function.
+ * @pipe: Pipe to cancel requests in.
+ * @transaction: Transaction to cancel, returned by the submit function.
*
* Returns: 0 or a negative error code.
*/
-static int cvmx_usb_cancel(struct cvmx_usb_state *usb, int pipe_handle,
- int submit_handle)
+static int cvmx_usb_cancel(struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe,
+ struct cvmx_usb_transaction *transaction)
{
- struct cvmx_usb_transaction *transaction;
- struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
-
- if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
- return -EINVAL;
- if (unlikely((submit_handle < 0) || (submit_handle >= MAX_TRANSACTIONS)))
- return -EINVAL;
-
- /* Fail if the pipe isn't open */
- if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
- return -EINVAL;
-
- transaction = usb->transaction + submit_handle;
-
- /* Fail if this transaction already completed */
- if (unlikely((transaction->flags & __CVMX_USB_TRANSACTION_FLAGS_IN_USE) == 0))
- return -EINVAL;
-
/*
* If the transaction is the HEAD of the queue and scheduled. We need to
* treat it special
* does is call cvmx_usb_cancel() in a loop.
*
* @usb: USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- * Pipe handle to cancel requests in.
+ * @pipe: Pipe to cancel requests in.
*
* Returns: 0 or a negative error code.
*/
-static int cvmx_usb_cancel_all(struct cvmx_usb_state *usb, int pipe_handle)
+static int cvmx_usb_cancel_all(struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe)
{
- struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
-
- if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
- return -EINVAL;
-
- /* Fail if the pipe isn't open */
- if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
- return -EINVAL;
-
/* Simply loop through and attempt to cancel each transaction */
while (pipe->head) {
- int result = cvmx_usb_cancel(usb, pipe_handle,
- __cvmx_usb_get_submit_handle(usb, pipe->head));
+ int result = cvmx_usb_cancel(usb, pipe, pipe->head);
if (unlikely(result != 0))
return result;
}
* Close a pipe created with cvmx_usb_open_pipe().
*
* @usb: USB device state populated by cvmx_usb_initialize().
- * @pipe_handle:
- * Pipe handle to close.
+ * @pipe: Pipe to close.
*
* 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, int pipe_handle)
+static int cvmx_usb_close_pipe(struct cvmx_usb_state *usb,
+ struct cvmx_usb_pipe *pipe)
{
- struct cvmx_usb_pipe *pipe = usb->pipe + pipe_handle;
-
- if (unlikely((pipe_handle < 0) || (pipe_handle >= MAX_PIPES)))
- return -EINVAL;
-
- /* Fail if the pipe isn't open */
- if (unlikely((pipe->flags & __CVMX_USB_PIPE_FLAGS_OPEN) == 0))
- return -EINVAL;
-
/* Fail if the pipe has pending transactions */
if (unlikely(pipe->head))
return -EBUSY;
- pipe->flags = 0;
__cvmx_usb_remove_pipe(&usb->idle_pipes, pipe);
- __cvmx_usb_append_pipe(&usb->free_pipes, pipe);
+ kfree(pipe);
return 0;
}
{
struct octeon_hcd *priv = hcd_to_octeon(hcd);
struct device *dev = hcd->self.controller;
- int submit_handle = -1;
- int pipe_handle;
+ struct cvmx_usb_transaction *transaction = NULL;
+ struct cvmx_usb_pipe *pipe;
unsigned long flags;
struct cvmx_usb_iso_packet *iso_packet;
struct usb_host_endpoint *ep = urb->ep;
dev = dev->parent;
}
}
- pipe_handle = cvmx_usb_open_pipe(&priv->usb,
- usb_pipedevice(urb->pipe),
- usb_pipeendpoint(urb->pipe),
- speed,
- le16_to_cpu(ep->desc.wMaxPacketSize) & 0x7ff,
- transfer_type,
- usb_pipein(urb->pipe) ? CVMX_USB_DIRECTION_IN : CVMX_USB_DIRECTION_OUT,
- urb->interval,
- (le16_to_cpu(ep->desc.wMaxPacketSize) >> 11) & 0x3,
- split_device,
- split_port);
- if (pipe_handle < 0) {
+ pipe = cvmx_usb_open_pipe(&priv->usb, usb_pipedevice(urb->pipe),
+ usb_pipeendpoint(urb->pipe), speed,
+ le16_to_cpu(ep->desc.wMaxPacketSize) & 0x7ff,
+ transfer_type,
+ usb_pipein(urb->pipe) ?
+ CVMX_USB_DIRECTION_IN :
+ CVMX_USB_DIRECTION_OUT,
+ urb->interval,
+ (le16_to_cpu(ep->desc.wMaxPacketSize) >> 11) & 0x3,
+ split_device, split_port);
+ if (!pipe) {
spin_unlock_irqrestore(&priv->lock, flags);
dev_dbg(dev, "Failed to create pipe\n");
return -ENOMEM;
}
- ep->hcpriv = (void *)(0x10000L + pipe_handle);
+ ep->hcpriv = pipe;
} else {
- pipe_handle = 0xffff & (long)ep->hcpriv;
+ pipe = ep->hcpriv;
}
switch (usb_pipetype(urb->pipe)) {
* this saves us a bunch of logic.
*/
urb->setup_packet = (char *)iso_packet;
- submit_handle = cvmx_usb_submit_isochronous(&priv->usb, pipe_handle,
- urb->start_frame,
- urb->number_of_packets,
- iso_packet,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- urb);
+ transaction = cvmx_usb_submit_isochronous(&priv->usb,
+ pipe, urb);
/*
* If submit failed we need to free our private packet
* list.
*/
- if (submit_handle < 0) {
+ if (!transaction) {
urb->setup_packet = NULL;
kfree(iso_packet);
}
case PIPE_INTERRUPT:
dev_dbg(dev, "Submit interrupt to %d.%d\n",
usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe));
- submit_handle = cvmx_usb_submit_interrupt(&priv->usb, pipe_handle,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- urb);
+ transaction = cvmx_usb_submit_interrupt(&priv->usb, pipe, urb);
break;
case PIPE_CONTROL:
dev_dbg(dev, "Submit control to %d.%d\n",
usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe));
- submit_handle = cvmx_usb_submit_control(&priv->usb, pipe_handle,
- urb);
+ transaction = cvmx_usb_submit_control(&priv->usb, pipe, urb);
break;
case PIPE_BULK:
dev_dbg(dev, "Submit bulk to %d.%d\n",
usb_pipedevice(urb->pipe), usb_pipeendpoint(urb->pipe));
- submit_handle = cvmx_usb_submit_bulk(&priv->usb, pipe_handle,
- urb);
+ transaction = cvmx_usb_submit_bulk(&priv->usb, pipe, urb);
break;
}
- if (submit_handle < 0) {
+ if (!transaction) {
spin_unlock_irqrestore(&priv->lock, flags);
dev_dbg(dev, "Failed to submit\n");
return -ENOMEM;
}
- urb->hcpriv = (void *)(long)(((submit_handle & 0xffff) << 16) | pipe_handle);
+ urb->hcpriv = transaction;
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static void octeon_usb_urb_dequeue_work(unsigned long arg)
{
+ struct urb *urb;
+ struct urb *next;
unsigned long flags;
struct octeon_hcd *priv = (struct octeon_hcd *)arg;
spin_lock_irqsave(&priv->lock, flags);
- while (!list_empty(&priv->dequeue_list)) {
- int pipe_handle;
- int submit_handle;
- struct urb *urb = container_of(priv->dequeue_list.next, struct urb, urb_list);
- list_del(&urb->urb_list);
- /* not enqueued on dequeue_list */
- INIT_LIST_HEAD(&urb->urb_list);
- pipe_handle = 0xffff & (long)urb->hcpriv;
- submit_handle = ((long)urb->hcpriv) >> 16;
- cvmx_usb_cancel(&priv->usb, pipe_handle, submit_handle);
+ list_for_each_entry_safe(urb, next, &priv->dequeue_list, urb_list) {
+ list_del_init(&urb->urb_list);
+ cvmx_usb_cancel(&priv->usb, urb->ep->hcpriv, urb->hcpriv);
}
spin_unlock_irqrestore(&priv->lock, flags);
if (ep->hcpriv) {
struct octeon_hcd *priv = hcd_to_octeon(hcd);
- int pipe_handle = 0xffff & (long)ep->hcpriv;
+ struct cvmx_usb_pipe *pipe = ep->hcpriv;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
- cvmx_usb_cancel_all(&priv->usb, pipe_handle);
- if (cvmx_usb_close_pipe(&priv->usb, pipe_handle))
- dev_dbg(dev, "Closing pipe %d failed\n", pipe_handle);
+ cvmx_usb_cancel_all(&priv->usb, pipe);
+ if (cvmx_usb_close_pipe(&priv->usb, pipe))
+ dev_dbg(dev, "Closing pipe %p failed\n", pipe);
spin_unlock_irqrestore(&priv->lock, flags);
ep->hcpriv = NULL;
}