Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
c3278f9f
Commit
c3278f9f
authored
Nov 18, 2014
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Plain Diff
greybus: Merge branch 'master' into vibrator-gb
parents
4b992018
de80073a
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
164 additions
and
149 deletions
+164
-149
drivers/staging/greybus/connection.c
drivers/staging/greybus/connection.c
+1
-1
drivers/staging/greybus/core.c
drivers/staging/greybus/core.c
+3
-5
drivers/staging/greybus/es1-ap-usb.c
drivers/staging/greybus/es1-ap-usb.c
+89
-79
drivers/staging/greybus/greybus.h
drivers/staging/greybus/greybus.h
+8
-8
drivers/staging/greybus/operation.c
drivers/staging/greybus/operation.c
+55
-43
drivers/staging/greybus/operation.h
drivers/staging/greybus/operation.h
+8
-13
No files found.
drivers/staging/greybus/connection.c
View file @
c3278f9f
...
@@ -40,7 +40,7 @@ void greybus_cport_in(struct greybus_host_device *hd, u16 cport_id,
...
@@ -40,7 +40,7 @@ void greybus_cport_in(struct greybus_host_device *hd, u16 cport_id,
"nonexistent connection (%zu bytes dropped)
\n
"
,
length
);
"nonexistent connection (%zu bytes dropped)
\n
"
,
length
);
return
;
return
;
}
}
gb_connection_
operation_
recv
(
connection
,
data
,
length
);
gb_connection_recv
(
connection
,
data
,
length
);
}
}
EXPORT_SYMBOL_GPL
(
greybus_cport_in
);
EXPORT_SYMBOL_GPL
(
greybus_cport_in
);
...
...
drivers/staging/greybus/core.c
View file @
c3278f9f
...
@@ -169,11 +169,9 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
...
@@ -169,11 +169,9 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
* Validate that the driver implements all of the callbacks
* Validate that the driver implements all of the callbacks
* so that we don't have to every time we make them.
* so that we don't have to every time we make them.
*/
*/
if
((
!
driver
->
alloc_gbuf_data
)
||
if
((
!
driver
->
buffer_alloc
)
||
(
!
driver
->
buffer_free
)
||
(
!
driver
->
free_gbuf_data
)
||
(
!
driver
->
buffer_send
)
||
(
!
driver
->
buffer_cancel
)
||
(
!
driver
->
submit_svc
)
||
(
!
driver
->
submit_svc
))
{
(
!
driver
->
submit_gbuf
)
||
(
!
driver
->
kill_gbuf
))
{
pr_err
(
"Must implement all greybus_host_driver callbacks!
\n
"
);
pr_err
(
"Must implement all greybus_host_driver callbacks!
\n
"
);
return
NULL
;
return
NULL
;
}
}
...
...
drivers/staging/greybus/es1-ap-usb.c
View file @
c3278f9f
...
@@ -20,7 +20,6 @@
...
@@ -20,7 +20,6 @@
#define ES1_SVC_MSG_SIZE (sizeof(struct svc_msg) + SZ_64K)
#define ES1_SVC_MSG_SIZE (sizeof(struct svc_msg) + SZ_64K)
#define ES1_GBUF_MSG_SIZE PAGE_SIZE
#define ES1_GBUF_MSG_SIZE PAGE_SIZE
static
const
struct
usb_device_id
id_table
[]
=
{
static
const
struct
usb_device_id
id_table
[]
=
{
/* Made up numbers for the SVC USB Bridge in ES1 */
/* Made up numbers for the SVC USB Bridge in ES1 */
{
USB_DEVICE
(
0xffff
,
0x0001
)
},
{
USB_DEVICE
(
0xffff
,
0x0001
)
},
...
@@ -86,70 +85,47 @@ static inline struct es1_ap_dev *hd_to_es1(struct greybus_host_device *hd)
...
@@ -86,70 +85,47 @@ static inline struct es1_ap_dev *hd_to_es1(struct greybus_host_device *hd)
static
void
cport_out_callback
(
struct
urb
*
urb
);
static
void
cport_out_callback
(
struct
urb
*
urb
);
/*
/*
* Allocate the actual buffer for this gbuf and device and cport
* Allocate a buffer to be sent via UniPro.
*
* We are responsible for setting the following fields in a struct gbuf:
* void *hcpriv;
* void *transfer_buffer;
* u32 transfer_buffer_length;
*/
*/
static
int
alloc_gbuf_data
(
struct
gbuf
*
gbuf
,
unsigned
int
size
,
static
void
*
buffer_alloc
(
unsigned
int
size
,
gfp_t
gfp_mask
)
gfp_t
gfp_mask
)
{
{
u32
cport_reserve
=
gbuf
->
dest_cport_id
==
CPORT_ID_BAD
?
0
:
1
;
u8
*
buffer
;
u8
*
buffer
;
if
(
gbuf
->
transfer_buffer
)
return
-
EALREADY
;
if
(
size
>
ES1_GBUF_MSG_SIZE
)
{
if
(
size
>
ES1_GBUF_MSG_SIZE
)
{
pr_err
(
"guf was asked to be bigger than %ld!
\n
"
,
pr_err
(
"guf was asked to be bigger than %ld!
\n
"
,
ES1_GBUF_MSG_SIZE
);
ES1_GBUF_MSG_SIZE
);
}
}
/* For ES2 we need to figure out what cport is going to what endpoint,
/*
* but for ES1, it's so dirt simple, we don't have a choice...
* For ES1 we need to insert a byte at the front of the data
* to indicate the destination CPort id. We only need one
* extra byte, but we allocate four extra bytes to allow the
* buffer returned to be aligned on a four-byte boundary.
*
*
* Also, do a "slow" allocation now, if we need speed, use a cache
* This is only needed for outbound data, but we handle
* buffers for inbound data the same way for consistency.
*
*
* For ES1 outbound buffers need to insert their target
* XXX Do we need to indicate the destination device id too?
* CPort Id before the data; set aside an extra byte for
* that purpose in that case.
*/
*/
buffer
=
kzalloc
(
cport_reserve
+
size
,
gfp_mask
);
buffer
=
kzalloc
(
GB_BUFFER_ALIGN
+
size
,
gfp_mask
);
if
(
!
buffer
)
if
(
buffer
)
return
-
ENOMEM
;
buffer
+=
GB_BUFFER_ALIGN
;
/* Insert the cport id for outbound buffers */
return
buffer
;
if
(
cport_reserve
)
{
if
(
gbuf
->
dest_cport_id
>
(
u16
)
U8_MAX
)
{
pr_err
(
"gbuf->dest_cport_id (%hd) is out of range!
\n
"
,
gbuf
->
dest_cport_id
);
kfree
(
buffer
);
return
-
EINVAL
;
}
*
buffer
++
=
gbuf
->
dest_cport_id
;
}
gbuf
->
transfer_buffer
=
buffer
;
gbuf
->
transfer_buffer_length
=
size
;
return
0
;
}
}
/* Free
the memory we allocated with a gbuf
*/
/* Free
a previously-allocated buffer
*/
static
void
free_gbuf_data
(
struct
gbuf
*
gbuf
)
static
void
buffer_free
(
void
*
buffer
)
{
{
u8
*
transfer_buffer
=
gbuf
->
transfer_
buffer
;
u8
*
allocated
=
buffer
;
/* Can be called with a NULL
transfer_
buffer on some error paths */
/* Can be called with a NULL buffer on some error paths */
if
(
!
transfer_buffer
)
if
(
!
allocated
)
return
;
return
;
/* Account for the cport id in outbound buffers */
/* Account for the space set aside for the prepended cport id */
if
(
gbuf
->
dest_cport_id
!=
CPORT_ID_BAD
)
allocated
-=
GB_BUFFER_ALIGN
;
transfer_buffer
--
;
/* Back up to cport id */
kfree
(
allocated
);
kfree
(
transfer_buffer
);
gbuf
->
transfer_buffer
=
NULL
;
}
}
#define ES1_TIMEOUT 500
/* 500 ms for the SVC to do something */
#define ES1_TIMEOUT 500
/* 500 ms for the SVC to do something */
...
@@ -207,53 +183,86 @@ static struct urb *next_free_urb(struct es1_ap_dev *es1, gfp_t gfp_mask)
...
@@ -207,53 +183,86 @@ static struct urb *next_free_urb(struct es1_ap_dev *es1, gfp_t gfp_mask)
return
urb
;
return
urb
;
}
}
static
int
submit_gbuf
(
struct
gbuf
*
gbuf
,
gfp_t
gfp_mask
)
/*
* Returns an opaque cookie value if successful, or a pointer coded
* error otherwise. If the caller wishes to cancel the in-flight
* buffer, it must supply the returned cookie to the cancel routine.
*/
static
void
*
buffer_send
(
struct
greybus_host_device
*
hd
,
u16
dest_cport_id
,
void
*
buffer
,
size_t
buffer_size
,
gfp_t
gfp_mask
)
{
{
struct
greybus_host_device
*
hd
=
gbuf
->
hd
;
struct
es1_ap_dev
*
es1
=
hd_to_es1
(
hd
);
struct
es1_ap_dev
*
es1
=
hd_to_es1
(
hd
);
struct
usb_device
*
udev
=
es1
->
usb_dev
;
struct
usb_device
*
udev
=
es1
->
usb_dev
;
u8
*
transfer_buffer
=
buffer
;
int
transfer_buffer_size
;
int
retval
;
int
retval
;
u8
*
transfer_buffer
;
u8
*
buffer
;
struct
urb
*
urb
;
struct
urb
*
urb
;
transfer_buffer
=
gbuf
->
transfer_buffer
;
if
(
!
buffer
)
{
if
(
!
transfer_buffer
)
pr_err
(
"null buffer supplied to send
\n
"
);
return
-
EINVAL
;
return
ERR_PTR
(
-
EINVAL
);
buffer
=
&
transfer_buffer
[
-
1
];
/* yes, we mean -1 */
}
if
(
buffer_size
>
(
size_t
)
INT_MAX
)
{
pr_err
(
"bad buffer size (%zu) supplied to send
\n
"
,
buffer_size
);
return
ERR_PTR
(
-
EINVAL
);
}
transfer_buffer
--
;
transfer_buffer_size
=
buffer_size
+
1
;
/*
* The data actually transferred will include an indication
* of where the data should be sent. Do one last check of
* the target CPort id before filling it in.
*/
if
(
dest_cport_id
==
CPORT_ID_BAD
)
{
pr_err
(
"request to send inbound data buffer
\n
"
);
return
ERR_PTR
(
-
EINVAL
);
}
if
(
dest_cport_id
>
(
u16
)
U8_MAX
)
{
pr_err
(
"dest_cport_id (%hd) is out of range for ES1
\n
"
,
dest_cport_id
);
return
ERR_PTR
(
-
EINVAL
);
}
/* OK, the destination is fine; record it in the transfer buffer */
*
transfer_buffer
=
dest_cport_id
;
/* Find a free urb */
/* Find a free urb */
urb
=
next_free_urb
(
es1
,
gfp_mask
);
urb
=
next_free_urb
(
es1
,
gfp_mask
);
if
(
!
urb
)
if
(
!
urb
)
return
-
ENOMEM
;
return
ERR_PTR
(
-
ENOMEM
);
gbuf
->
hcd_data
=
urb
;
usb_fill_bulk_urb
(
urb
,
udev
,
usb_fill_bulk_urb
(
urb
,
udev
,
usb_sndbulkpipe
(
udev
,
es1
->
cport_out_endpoint
),
usb_sndbulkpipe
(
udev
,
es1
->
cport_out_endpoint
),
buffer
,
gbuf
->
transfer_buffer_length
+
1
,
transfer_buffer
,
transfer_buffer_size
,
cport_out_callback
,
gbuf
);
cport_out_callback
,
hd
);
retval
=
usb_submit_urb
(
urb
,
gfp_mask
);
retval
=
usb_submit_urb
(
urb
,
gfp_mask
);
return
retval
;
if
(
retval
)
{
pr_err
(
"error %d submitting URB
\n
"
,
retval
);
return
ERR_PTR
(
retval
);
}
return
urb
;
}
}
static
void
kill_gbuf
(
struct
gbuf
*
gbuf
)
static
void
buffer_cancel
(
void
*
cookie
)
{
{
struct
urb
*
urb
=
gbuf
->
hcd_data
;
struct
urb
*
urb
=
cookie
;
if
(
!
urb
)
return
;
/*
* We really should be defensive and track all outstanding
* (sent) buffers rather than trusting the cookie provided
* is valid. For the time being, this will do.
*/
usb_kill_urb
(
urb
);
usb_kill_urb
(
urb
);
}
}
static
struct
greybus_host_driver
es1_driver
=
{
static
struct
greybus_host_driver
es1_driver
=
{
.
hd_priv_size
=
sizeof
(
struct
es1_ap_dev
),
.
hd_priv_size
=
sizeof
(
struct
es1_ap_dev
),
.
alloc_gbuf_data
=
alloc_gbuf_data
,
.
buffer_alloc
=
buffer_alloc
,
.
free_gbuf_data
=
free_gbuf_data
,
.
buffer_free
=
buffer_free
,
.
buffer_send
=
buffer_send
,
.
buffer_cancel
=
buffer_cancel
,
.
submit_svc
=
submit_svc
,
.
submit_svc
=
submit_svc
,
.
submit_gbuf
=
submit_gbuf
,
.
kill_gbuf
=
kill_gbuf
,
};
};
/* Common function to report consistent warnings based on URB status */
/* Common function to report consistent warnings based on URB status */
...
@@ -329,7 +338,8 @@ static void ap_disconnect(struct usb_interface *interface)
...
@@ -329,7 +338,8 @@ static void ap_disconnect(struct usb_interface *interface)
/* Callback for when we get a SVC message */
/* Callback for when we get a SVC message */
static
void
svc_in_callback
(
struct
urb
*
urb
)
static
void
svc_in_callback
(
struct
urb
*
urb
)
{
{
struct
es1_ap_dev
*
es1
=
urb
->
context
;
struct
greybus_host_device
*
hd
=
urb
->
context
;
struct
es1_ap_dev
*
es1
=
hd_to_es1
(
hd
);
struct
device
*
dev
=
&
urb
->
dev
->
dev
;
struct
device
*
dev
=
&
urb
->
dev
->
dev
;
int
status
=
check_urb_status
(
urb
);
int
status
=
check_urb_status
(
urb
);
int
retval
;
int
retval
;
...
@@ -355,8 +365,9 @@ static void svc_in_callback(struct urb *urb)
...
@@ -355,8 +365,9 @@ static void svc_in_callback(struct urb *urb)
static
void
cport_in_callback
(
struct
urb
*
urb
)
static
void
cport_in_callback
(
struct
urb
*
urb
)
{
{
struct
greybus_host_device
*
hd
=
urb
->
context
;
struct
es1_ap_dev
*
es1
=
hd_to_es1
(
hd
);
struct
device
*
dev
=
&
urb
->
dev
->
dev
;
struct
device
*
dev
=
&
urb
->
dev
->
dev
;
struct
es1_ap_dev
*
es1
=
urb
->
context
;
int
status
=
check_urb_status
(
urb
);
int
status
=
check_urb_status
(
urb
);
int
retval
;
int
retval
;
u8
cport
;
u8
cport
;
...
@@ -396,15 +407,12 @@ static void cport_in_callback(struct urb *urb)
...
@@ -396,15 +407,12 @@ static void cport_in_callback(struct urb *urb)
static
void
cport_out_callback
(
struct
urb
*
urb
)
static
void
cport_out_callback
(
struct
urb
*
urb
)
{
{
struct
g
buf
*
gbuf
=
urb
->
context
;
struct
g
reybus_host_device
*
hd
=
urb
->
context
;
struct
es1_ap_dev
*
es1
=
hd_to_es1
(
gbuf
->
hd
);
struct
es1_ap_dev
*
es1
=
hd_to_es1
(
hd
);
unsigned
long
flags
;
unsigned
long
flags
;
/* int status = check_urb_status(urb); */
int
i
;
int
i
;
/* Record whether the transfer was successful */
gbuf
->
status
=
check_urb_status
(
urb
);
gbuf
->
hcd_data
=
NULL
;
/*
/*
* See if this was an urb in our pool, if so mark it "free", otherwise
* See if this was an urb in our pool, if so mark it "free", otherwise
* we need to free it ourselves.
* we need to free it ourselves.
...
@@ -423,6 +431,8 @@ static void cport_out_callback(struct urb *urb)
...
@@ -423,6 +431,8 @@ static void cport_out_callback(struct urb *urb)
usb_free_urb
(
urb
);
usb_free_urb
(
urb
);
/*
/*
* Rest assured Greg, this craziness is getting fixed.
*
* Yes, you are right, we aren't telling anyone that the urb finished.
* Yes, you are right, we aren't telling anyone that the urb finished.
* "That's crazy! How does this all even work?" you might be saying.
* "That's crazy! How does this all even work?" you might be saying.
* The "magic" is the idea that greybus works on the "operation" level,
* The "magic" is the idea that greybus works on the "operation" level,
...
@@ -529,7 +539,7 @@ static int ap_probe(struct usb_interface *interface,
...
@@ -529,7 +539,7 @@ static int ap_probe(struct usb_interface *interface,
usb_fill_int_urb
(
es1
->
svc_urb
,
udev
,
usb_fill_int_urb
(
es1
->
svc_urb
,
udev
,
usb_rcvintpipe
(
udev
,
es1
->
svc_endpoint
),
usb_rcvintpipe
(
udev
,
es1
->
svc_endpoint
),
es1
->
svc_buffer
,
ES1_SVC_MSG_SIZE
,
svc_in_callback
,
es1
->
svc_buffer
,
ES1_SVC_MSG_SIZE
,
svc_in_callback
,
es1
,
svc_interval
);
hd
,
svc_interval
);
retval
=
usb_submit_urb
(
es1
->
svc_urb
,
GFP_KERNEL
);
retval
=
usb_submit_urb
(
es1
->
svc_urb
,
GFP_KERNEL
);
if
(
retval
)
if
(
retval
)
goto
error
;
goto
error
;
...
@@ -549,7 +559,7 @@ static int ap_probe(struct usb_interface *interface,
...
@@ -549,7 +559,7 @@ static int ap_probe(struct usb_interface *interface,
usb_fill_bulk_urb
(
urb
,
udev
,
usb_fill_bulk_urb
(
urb
,
udev
,
usb_rcvbulkpipe
(
udev
,
es1
->
cport_in_endpoint
),
usb_rcvbulkpipe
(
udev
,
es1
->
cport_in_endpoint
),
buffer
,
ES1_GBUF_MSG_SIZE
,
cport_in_callback
,
buffer
,
ES1_GBUF_MSG_SIZE
,
cport_in_callback
,
es1
);
hd
);
es1
->
cport_in_urb
[
i
]
=
urb
;
es1
->
cport_in_urb
[
i
]
=
urb
;
es1
->
cport_in_buffer
[
i
]
=
buffer
;
es1
->
cport_in_buffer
[
i
]
=
buffer
;
retval
=
usb_submit_urb
(
urb
,
GFP_KERNEL
);
retval
=
usb_submit_urb
(
urb
,
GFP_KERNEL
);
...
...
drivers/staging/greybus/greybus.h
View file @
c3278f9f
...
@@ -68,7 +68,9 @@
...
@@ -68,7 +68,9 @@
struct
greybus_host_device
;
struct
greybus_host_device
;
struct
svc_msg
;
struct
svc_msg
;
struct
gbuf
;
/* Buffers allocated from the host driver will be aligned to this multiple */
#define GB_BUFFER_ALIGN sizeof(u32)
/* Greybus "Host driver" structure, needed by a host controller driver to be
/* Greybus "Host driver" structure, needed by a host controller driver to be
* able to handle both SVC control as well as "real" greybus messages
* able to handle both SVC control as well as "real" greybus messages
...
@@ -76,13 +78,13 @@ struct gbuf;
...
@@ -76,13 +78,13 @@ struct gbuf;
struct
greybus_host_driver
{
struct
greybus_host_driver
{
size_t
hd_priv_size
;
size_t
hd_priv_size
;
int
(
*
alloc_gbuf_data
)(
struct
gbuf
*
gbuf
,
unsigned
int
size
,
void
*
(
*
buffer_alloc
)(
unsigned
int
size
,
gfp_t
gfp_mask
);
gfp_t
gfp_mask
);
void
(
*
buffer_free
)(
void
*
buffer
);
void
(
*
free_gbuf_data
)(
struct
gbuf
*
gbuf
);
void
*
(
*
buffer_send
)(
struct
greybus_host_device
*
hd
,
u16
dest_cport_id
,
void
*
buffer
,
size_t
buffer_size
,
gfp_t
gfp_mask
);
void
(
*
buffer_cancel
)(
void
*
cookie
);
int
(
*
submit_svc
)(
struct
svc_msg
*
svc_msg
,
int
(
*
submit_svc
)(
struct
svc_msg
*
svc_msg
,
struct
greybus_host_device
*
hd
);
struct
greybus_host_device
*
hd
);
int
(
*
submit_gbuf
)(
struct
gbuf
*
gbuf
,
gfp_t
gfp_mask
);
void
(
*
kill_gbuf
)(
struct
gbuf
*
gbuf
);
};
};
struct
greybus_host_device
{
struct
greybus_host_device
{
...
@@ -153,8 +155,6 @@ int gb_ap_init(void);
...
@@ -153,8 +155,6 @@ int gb_ap_init(void);
void
gb_ap_exit
(
void
);
void
gb_ap_exit
(
void
);
int
gb_debugfs_init
(
void
);
int
gb_debugfs_init
(
void
);
void
gb_debugfs_cleanup
(
void
);
void
gb_debugfs_cleanup
(
void
);
int
gb_gbuf_init
(
void
);
void
gb_gbuf_exit
(
void
);
extern
struct
bus_type
greybus_bus_type
;
extern
struct
bus_type
greybus_bus_type
;
extern
const
struct
attribute_group
*
greybus_module_groups
[];
extern
const
struct
attribute_group
*
greybus_module_groups
[];
...
...
drivers/staging/greybus/operation.c
View file @
c3278f9f
...
@@ -72,7 +72,7 @@ static void gb_pending_operation_insert(struct gb_operation *operation)
...
@@ -72,7 +72,7 @@ static void gb_pending_operation_insert(struct gb_operation *operation)
spin_unlock_irq
(
&
gb_operations_lock
);
spin_unlock_irq
(
&
gb_operations_lock
);
/* Store the operation id in the request header */
/* Store the operation id in the request header */
header
=
operation
->
request
.
gbuf
.
transfer_
buffer
;
header
=
operation
->
request
.
buffer
;
header
->
id
=
cpu_to_le16
(
operation
->
id
);
header
->
id
=
cpu_to_le16
(
operation
->
id
);
}
}
...
@@ -103,20 +103,37 @@ gb_pending_operation_find(struct gb_connection *connection, u16 id)
...
@@ -103,20 +103,37 @@ gb_pending_operation_find(struct gb_connection *connection, u16 id)
return
found
?
operation
:
NULL
;
return
found
?
operation
:
NULL
;
}
}
static
int
g
reybus_submit_gbuf
(
struct
gbuf
*
gbuf
,
gfp_t
gfp_mask
)
static
int
g
b_message_send
(
struct
gb_message
*
message
,
gfp_t
gfp_mask
)
{
{
gbuf
->
status
=
-
EINPROGRESS
;
struct
gb_connection
*
connection
=
message
->
operation
->
connection
;
u16
dest_cport_id
=
connection
->
interface_cport_id
;
return
gbuf
->
hd
->
driver
->
submit_gbuf
(
gbuf
,
gfp_mask
);
message
->
status
=
-
EINPROGRESS
;
message
->
cookie
=
connection
->
hd
->
driver
->
buffer_send
(
connection
->
hd
,
dest_cport_id
,
message
->
buffer
,
message
->
buffer_size
,
gfp_mask
);
if
(
IS_ERR
(
message
->
cookie
))
{
message
->
status
=
PTR_ERR
(
message
->
cookie
);
message
->
cookie
=
NULL
;
return
message
->
status
;
}
return
0
;
}
}
static
void
g
reybus_kill_gbuf
(
struct
gbuf
*
gbuf
)
static
void
g
b_message_cancel
(
struct
gb_message
*
message
)
{
{
if
(
gbuf
->
status
!=
-
EINPROGRESS
)
struct
greybus_host_device
*
hd
;
if
(
message
->
status
!=
-
EINPROGRESS
)
return
;
return
;
gbuf
->
hd
->
driver
->
kill_gbuf
(
gbuf
);
hd
=
message
->
operation
->
connection
->
hd
;
hd
->
driver
->
buffer_cancel
(
message
->
cookie
);
}
}
/*
/*
* An operations's response message has arrived. If no callback was
* An operations's response message has arrived. If no callback was
* supplied it was submitted for asynchronous completion, so we notify
* supplied it was submitted for asynchronous completion, so we notify
...
@@ -139,7 +156,7 @@ int gb_operation_wait(struct gb_operation *operation)
...
@@ -139,7 +156,7 @@ int gb_operation_wait(struct gb_operation *operation)
ret
=
wait_for_completion_interruptible
(
&
operation
->
completion
);
ret
=
wait_for_completion_interruptible
(
&
operation
->
completion
);
/* If interrupted, cancel the in-flight buffer */
/* If interrupted, cancel the in-flight buffer */
if
(
ret
<
0
)
if
(
ret
<
0
)
g
reybus_kill_gbuf
(
&
operation
->
request
.
gbuf
);
g
b_message_cancel
(
&
operation
->
request
);
return
ret
;
return
ret
;
}
}
...
@@ -149,7 +166,7 @@ static void gb_operation_request_handle(struct gb_operation *operation)
...
@@ -149,7 +166,7 @@ static void gb_operation_request_handle(struct gb_operation *operation)
struct
gb_protocol
*
protocol
=
operation
->
connection
->
protocol
;
struct
gb_protocol
*
protocol
=
operation
->
connection
->
protocol
;
struct
gb_operation_msg_hdr
*
header
;
struct
gb_operation_msg_hdr
*
header
;
header
=
operation
->
request
.
gbuf
.
transfer_
buffer
;
header
=
operation
->
request
.
buffer
;
/*
/*
* If the protocol has no incoming request handler, report
* If the protocol has no incoming request handler, report
...
@@ -179,7 +196,7 @@ static void gb_operation_recv_work(struct work_struct *recv_work)
...
@@ -179,7 +196,7 @@ static void gb_operation_recv_work(struct work_struct *recv_work)
bool
incoming_request
;
bool
incoming_request
;
operation
=
container_of
(
recv_work
,
struct
gb_operation
,
recv_work
);
operation
=
container_of
(
recv_work
,
struct
gb_operation
,
recv_work
);
incoming_request
=
operation
->
response
.
gbuf
.
transfer_
buffer
==
NULL
;
incoming_request
=
operation
->
response
.
buffer
==
NULL
;
if
(
incoming_request
)
if
(
incoming_request
)
gb_operation_request_handle
(
operation
);
gb_operation_request_handle
(
operation
);
gb_operation_complete
(
operation
);
gb_operation_complete
(
operation
);
...
@@ -213,16 +230,12 @@ static void operation_timeout(struct work_struct *work)
...
@@ -213,16 +230,12 @@ static void operation_timeout(struct work_struct *work)
*/
*/
static
int
gb_operation_message_init
(
struct
gb_operation
*
operation
,
static
int
gb_operation_message_init
(
struct
gb_operation
*
operation
,
u8
type
,
size_t
size
,
u8
type
,
size_t
size
,
bool
request
,
bool
data_out
)
bool
request
,
gfp_t
gfp_flags
)
{
{
struct
gb_connection
*
connection
=
operation
->
connection
;
struct
gb_connection
*
connection
=
operation
->
connection
;
struct
greybus_host_device
*
hd
=
connection
->
hd
;
struct
greybus_host_device
*
hd
=
connection
->
hd
;
struct
gb_message
*
message
;
struct
gb_message
*
message
;
struct
gb_operation_msg_hdr
*
header
;
struct
gb_operation_msg_hdr
*
header
;
struct
gbuf
*
gbuf
;
gfp_t
gfp_flags
=
data_out
?
GFP_KERNEL
:
GFP_ATOMIC
;
u16
dest_cport_id
;
int
ret
;
if
(
size
>
GB_OPERATION_MESSAGE_SIZE_MAX
)
if
(
size
>
GB_OPERATION_MESSAGE_SIZE_MAX
)
return
-
E2BIG
;
return
-
E2BIG
;
...
@@ -234,22 +247,15 @@ static int gb_operation_message_init(struct gb_operation *operation,
...
@@ -234,22 +247,15 @@ static int gb_operation_message_init(struct gb_operation *operation,
message
=
&
operation
->
response
;
message
=
&
operation
->
response
;
type
|=
GB_OPERATION_TYPE_RESPONSE
;
type
|=
GB_OPERATION_TYPE_RESPONSE
;
}
}
gbuf
=
&
message
->
gbuf
;
if
(
data_out
)
dest_cport_id
=
connection
->
interface_cport_id
;
else
dest_cport_id
=
CPORT_ID_BAD
;
gbuf
->
hd
=
hd
;
message
->
buffer
=
hd
->
driver
->
buffer_alloc
(
size
,
gfp_flags
);
gbuf
->
dest_cport_id
=
dest_cport_id
;
if
(
!
message
->
buffer
)
gbuf
->
status
=
-
EBADR
;
/* Initial value--means "never set" */
return
-
ENOMEM
;
ret
=
hd
->
driver
->
alloc_gbuf_data
(
gbuf
,
size
,
gfp_flags
);
message
->
buffer_size
=
size
;
if
(
ret
)
message
->
status
=
-
EBADR
;
/* Initial value--means "never set" */
return
ret
;
/* Fill in the header structure */
/* Fill in the header structure */
header
=
(
struct
gb_operation_msg_hdr
*
)
gbuf
->
transfer_
buffer
;
header
=
message
->
buffer
;
header
->
size
=
cpu_to_le16
(
size
);
header
->
size
=
cpu_to_le16
(
size
);
header
->
id
=
0
;
/* Filled in when submitted */
header
->
id
=
0
;
/* Filled in when submitted */
header
->
type
=
type
;
header
->
type
=
type
;
...
@@ -262,9 +268,15 @@ static int gb_operation_message_init(struct gb_operation *operation,
...
@@ -262,9 +268,15 @@ static int gb_operation_message_init(struct gb_operation *operation,
static
void
gb_operation_message_exit
(
struct
gb_message
*
message
)
static
void
gb_operation_message_exit
(
struct
gb_message
*
message
)
{
{
struct
greybus_host_device
*
hd
;
hd
=
message
->
operation
->
connection
->
hd
;
hd
->
driver
->
buffer_free
(
message
->
buffer
);
message
->
operation
=
NULL
;
message
->
operation
=
NULL
;
message
->
payload
=
NULL
;
message
->
payload
=
NULL
;
message
->
gbuf
.
hd
->
driver
->
free_gbuf_data
(
&
message
->
gbuf
);
message
->
buffer
=
NULL
;
message
->
buffer_size
=
0
;
}
}
/*
/*
...
@@ -298,13 +310,13 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection,
...
@@ -298,13 +310,13 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection,
operation
->
connection
=
connection
;
operation
->
connection
=
connection
;
ret
=
gb_operation_message_init
(
operation
,
type
,
request_size
,
ret
=
gb_operation_message_init
(
operation
,
type
,
request_size
,
true
,
outgoing
);
true
,
gfp_flags
);
if
(
ret
)
if
(
ret
)
goto
err_cache
;
goto
err_cache
;
if
(
outgoing
)
{
if
(
outgoing
)
{
ret
=
gb_operation_message_init
(
operation
,
type
,
response_size
,
ret
=
gb_operation_message_init
(
operation
,
type
,
response_size
,
false
,
false
);
false
,
GFP_KERNEL
);
if
(
ret
)
if
(
ret
)
goto
err_request
;
goto
err_request
;
}
}
...
@@ -377,11 +389,11 @@ int gb_operation_request_send(struct gb_operation *operation,
...
@@ -377,11 +389,11 @@ int gb_operation_request_send(struct gb_operation *operation,
* XXX
* XXX
* I think the order of operations is going to be
* I think the order of operations is going to be
* significant, and if so, we may need a mutex to surround
* significant, and if so, we may need a mutex to surround
* setting the operation id and submitting the
gbuf
.
* setting the operation id and submitting the
buffer
.
*/
*/
operation
->
callback
=
callback
;
operation
->
callback
=
callback
;
gb_pending_operation_insert
(
operation
);
gb_pending_operation_insert
(
operation
);
ret
=
g
reybus_submit_gbuf
(
&
operation
->
request
.
gbuf
,
GFP_KERNEL
);
ret
=
g
b_message_send
(
&
operation
->
request
,
GFP_KERNEL
);
if
(
ret
)
if
(
ret
)
return
ret
;
return
ret
;
...
@@ -418,12 +430,12 @@ int gb_operation_response_send(struct gb_operation *operation)
...
@@ -418,12 +430,12 @@ int gb_operation_response_send(struct gb_operation *operation)
* data into the buffer and do remaining handling via a work queue.
* data into the buffer and do remaining handling via a work queue.
*
*
*/
*/
void
gb_connection_
operation_
recv
(
struct
gb_connection
*
connection
,
void
gb_connection_recv
(
struct
gb_connection
*
connection
,
void
*
data
,
size_t
size
)
void
*
data
,
size_t
size
)
{
{
struct
gb_operation_msg_hdr
*
header
;
struct
gb_operation_msg_hdr
*
header
;
struct
gb_operation
*
operation
;
struct
gb_operation
*
operation
;
struct
gb
uf
*
gbuf
;
struct
gb
_message
*
message
;
u16
msg_size
;
u16
msg_size
;
if
(
connection
->
state
!=
GB_CONNECTION_STATE_ENABLED
)
if
(
connection
->
state
!=
GB_CONNECTION_STATE_ENABLED
)
...
@@ -446,8 +458,8 @@ void gb_connection_operation_recv(struct gb_connection *connection,
...
@@ -446,8 +458,8 @@ void gb_connection_operation_recv(struct gb_connection *connection,
}
}
cancel_delayed_work
(
&
operation
->
timeout_work
);
cancel_delayed_work
(
&
operation
->
timeout_work
);
gb_pending_operation_remove
(
operation
);
gb_pending_operation_remove
(
operation
);
gbuf
=
&
operation
->
response
.
gbuf
;
message
=
&
operation
->
response
;
if
(
size
>
gbuf
->
transfer_buffer_length
)
{
if
(
size
>
message
->
buffer_size
)
{
operation
->
result
=
GB_OP_OVERFLOW
;
operation
->
result
=
GB_OP_OVERFLOW
;
gb_connection_err
(
connection
,
"recv buffer too small"
);
gb_connection_err
(
connection
,
"recv buffer too small"
);
return
;
return
;
...
@@ -461,10 +473,10 @@ void gb_connection_operation_recv(struct gb_connection *connection,
...
@@ -461,10 +473,10 @@ void gb_connection_operation_recv(struct gb_connection *connection,
gb_connection_err
(
connection
,
"can't create operation"
);
gb_connection_err
(
connection
,
"can't create operation"
);
return
;
return
;
}
}
gbuf
=
&
operation
->
request
.
gbuf
;
message
=
&
operation
->
request
;
}
}
memcpy
(
gbuf
->
transfer_
buffer
,
data
,
msg_size
);
memcpy
(
message
->
buffer
,
data
,
msg_size
);
/* The rest will be handled in work queue context */
/* The rest will be handled in work queue context */
queue_work
(
gb_operation_recv_workqueue
,
&
operation
->
recv_work
);
queue_work
(
gb_operation_recv_workqueue
,
&
operation
->
recv_work
);
...
@@ -476,9 +488,9 @@ void gb_connection_operation_recv(struct gb_connection *connection,
...
@@ -476,9 +488,9 @@ void gb_connection_operation_recv(struct gb_connection *connection,
void
gb_operation_cancel
(
struct
gb_operation
*
operation
)
void
gb_operation_cancel
(
struct
gb_operation
*
operation
)
{
{
operation
->
canceled
=
true
;
operation
->
canceled
=
true
;
g
reybus_kill_gbuf
(
&
operation
->
request
.
gbuf
);
g
b_message_cancel
(
&
operation
->
request
);
if
(
operation
->
response
.
gbuf
.
transfer_
buffer
)
if
(
operation
->
response
.
buffer
)
g
reybus_kill_gbuf
(
&
operation
->
response
.
gbuf
);
g
b_message_cancel
(
&
operation
->
response
);
}
}
int
gb_operation_init
(
void
)
int
gb_operation_init
(
void
)
...
...
drivers/staging/greybus/operation.h
View file @
c3278f9f
...
@@ -24,21 +24,16 @@ enum gb_operation_status {
...
@@ -24,21 +24,16 @@ enum gb_operation_status {
GB_OP_TIMEOUT
=
0xff
,
GB_OP_TIMEOUT
=
0xff
,
};
};
struct
gbuf
{
struct
greybus_host_device
*
hd
;
u16
dest_cport_id
;
/* Destination CPort id */
int
status
;
void
*
transfer_buffer
;
u32
transfer_buffer_length
;
void
*
hcd_data
;
/* for the HCD to track the gbuf */
};
struct
gb_message
{
struct
gb_message
{
void
*
payload
;
void
*
payload
;
struct
gb_operation
*
operation
;
struct
gb_operation
*
operation
;
struct
gbuf
gbuf
;
int
status
;
void
*
buffer
;
size_t
buffer_size
;
void
*
cookie
;
};
};
/*
/*
...
@@ -87,7 +82,7 @@ struct gb_operation {
...
@@ -87,7 +82,7 @@ struct gb_operation {
struct
list_head
links
;
/* connection->{operations,pending} */
struct
list_head
links
;
/* connection->{operations,pending} */
};
};
void
gb_connection_
operation_
recv
(
struct
gb_connection
*
connection
,
void
gb_connection_recv
(
struct
gb_connection
*
connection
,
void
*
data
,
size_t
size
);
void
*
data
,
size_t
size
);
struct
gb_operation
*
gb_operation_create
(
struct
gb_connection
*
connection
,
struct
gb_operation
*
gb_operation_create
(
struct
gb_connection
*
connection
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment