2017-12-12 02:43:05 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2011 - 2017 , The Linux Foundation
*/
# include <linux/irq.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/io.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
# include <linux/delay.h>
# include <linux/clk.h>
# include <linux/of.h>
2017-12-12 02:43:06 +03:00
# include <linux/pm_runtime.h>
2017-12-12 02:43:05 +03:00
# include "slimbus.h"
/* Manager registers */
# define MGR_CFG 0x200
# define MGR_STATUS 0x204
# define MGR_INT_EN 0x210
# define MGR_INT_STAT 0x214
# define MGR_INT_CLR 0x218
# define MGR_TX_MSG 0x230
# define MGR_RX_MSG 0x270
# define MGR_IE_STAT 0x2F0
# define MGR_VE_STAT 0x300
# define MGR_CFG_ENABLE 1
/* Framer registers */
# define FRM_CFG 0x400
# define FRM_STAT 0x404
# define FRM_INT_EN 0x410
# define FRM_INT_STAT 0x414
# define FRM_INT_CLR 0x418
# define FRM_WAKEUP 0x41C
# define FRM_CLKCTL_DONE 0x420
# define FRM_IE_STAT 0x430
# define FRM_VE_STAT 0x440
/* Interface registers */
# define INTF_CFG 0x600
# define INTF_STAT 0x604
# define INTF_INT_EN 0x610
# define INTF_INT_STAT 0x614
# define INTF_INT_CLR 0x618
# define INTF_IE_STAT 0x630
# define INTF_VE_STAT 0x640
/* Interrupt status bits */
# define MGR_INT_TX_NACKED_2 BIT(25)
# define MGR_INT_MSG_BUF_CONTE BIT(26)
# define MGR_INT_RX_MSG_RCVD BIT(30)
# define MGR_INT_TX_MSG_SENT BIT(31)
/* Framer config register settings */
# define FRM_ACTIVE 1
# define CLK_GEAR 7
# define ROOT_FREQ 11
# define REF_CLK_GEAR 15
# define INTR_WAKE 19
# define SLIM_MSG_ASM_FIRST_WORD(l, mt, mc, dt, ad) \
( ( l ) | ( ( mt ) < < 5 ) | ( ( mc ) < < 8 ) | ( ( dt ) < < 15 ) | ( ( ad ) < < 16 ) )
# define SLIM_ROOT_FREQ 24576000
2017-12-12 02:43:06 +03:00
# define QCOM_SLIM_AUTOSUSPEND 1000
2017-12-12 02:43:05 +03:00
/* MAX message size over control channel */
# define SLIM_MSGQ_BUF_LEN 40
# define QCOM_TX_MSGS 2
# define QCOM_RX_MSGS 8
# define QCOM_BUF_ALLOC_RETRIES 10
# define CFG_PORT(r, v) ((v) ? CFG_PORT_V2(r) : CFG_PORT_V1(r))
/* V2 Component registers */
# define CFG_PORT_V2(r) ((r ## _V2))
# define COMP_CFG_V2 4
# define COMP_TRUST_CFG_V2 0x3000
/* V1 Component registers */
# define CFG_PORT_V1(r) ((r ## _V1))
# define COMP_CFG_V1 0
# define COMP_TRUST_CFG_V1 0x14
/* Resource group info for manager, and non-ported generic device-components */
# define EE_MGR_RSC_GRP (1 << 10)
# define EE_NGD_2 (2 << 6)
# define EE_NGD_1 0
struct slim_ctrl_buf {
void * base ;
spinlock_t lock ;
int head ;
int tail ;
int sl_sz ;
int n ;
} ;
struct qcom_slim_ctrl {
struct slim_controller ctrl ;
struct slim_framer framer ;
struct device * dev ;
void __iomem * base ;
void __iomem * slew_reg ;
struct slim_ctrl_buf rx ;
struct slim_ctrl_buf tx ;
struct completion * * wr_comp ;
int irq ;
struct workqueue_struct * rxwq ;
struct work_struct wd ;
struct clk * rclk ;
struct clk * hclk ;
} ;
static void qcom_slim_queue_tx ( struct qcom_slim_ctrl * ctrl , void * buf ,
u8 len , u32 tx_reg )
{
int count = ( len + 3 ) > > 2 ;
__iowrite32_copy ( ctrl - > base + tx_reg , buf , count ) ;
/* Ensure Oder of subsequent writes */
mb ( ) ;
}
static void * slim_alloc_rxbuf ( struct qcom_slim_ctrl * ctrl )
{
unsigned long flags ;
int idx ;
spin_lock_irqsave ( & ctrl - > rx . lock , flags ) ;
if ( ( ctrl - > rx . tail + 1 ) % ctrl - > rx . n = = ctrl - > rx . head ) {
spin_unlock_irqrestore ( & ctrl - > rx . lock , flags ) ;
dev_err ( ctrl - > dev , " RX QUEUE full! " ) ;
return NULL ;
}
idx = ctrl - > rx . tail ;
ctrl - > rx . tail = ( ctrl - > rx . tail + 1 ) % ctrl - > rx . n ;
spin_unlock_irqrestore ( & ctrl - > rx . lock , flags ) ;
return ctrl - > rx . base + ( idx * ctrl - > rx . sl_sz ) ;
}
2018-01-02 20:54:21 +03:00
static void slim_ack_txn ( struct qcom_slim_ctrl * ctrl , int err )
2017-12-12 02:43:05 +03:00
{
struct completion * comp ;
unsigned long flags ;
int idx ;
spin_lock_irqsave ( & ctrl - > tx . lock , flags ) ;
idx = ctrl - > tx . head ;
ctrl - > tx . head = ( ctrl - > tx . head + 1 ) % ctrl - > tx . n ;
spin_unlock_irqrestore ( & ctrl - > tx . lock , flags ) ;
comp = ctrl - > wr_comp [ idx ] ;
ctrl - > wr_comp [ idx ] = NULL ;
complete ( comp ) ;
}
static irqreturn_t qcom_slim_handle_tx_irq ( struct qcom_slim_ctrl * ctrl ,
u32 stat )
{
int err = 0 ;
if ( stat & MGR_INT_TX_MSG_SENT )
writel_relaxed ( MGR_INT_TX_MSG_SENT ,
ctrl - > base + MGR_INT_CLR ) ;
if ( stat & MGR_INT_TX_NACKED_2 ) {
u32 mgr_stat = readl_relaxed ( ctrl - > base + MGR_STATUS ) ;
u32 mgr_ie_stat = readl_relaxed ( ctrl - > base + MGR_IE_STAT ) ;
u32 frm_stat = readl_relaxed ( ctrl - > base + FRM_STAT ) ;
u32 frm_cfg = readl_relaxed ( ctrl - > base + FRM_CFG ) ;
u32 frm_intr_stat = readl_relaxed ( ctrl - > base + FRM_INT_STAT ) ;
u32 frm_ie_stat = readl_relaxed ( ctrl - > base + FRM_IE_STAT ) ;
u32 intf_stat = readl_relaxed ( ctrl - > base + INTF_STAT ) ;
u32 intf_intr_stat = readl_relaxed ( ctrl - > base + INTF_INT_STAT ) ;
u32 intf_ie_stat = readl_relaxed ( ctrl - > base + INTF_IE_STAT ) ;
writel_relaxed ( MGR_INT_TX_NACKED_2 , ctrl - > base + MGR_INT_CLR ) ;
dev_err ( ctrl - > dev , " TX Nack MGR:int:0x%x, stat:0x%x \n " ,
stat , mgr_stat ) ;
dev_err ( ctrl - > dev , " TX Nack MGR:ie:0x%x \n " , mgr_ie_stat ) ;
dev_err ( ctrl - > dev , " TX Nack FRM:int:0x%x, stat:0x%x \n " ,
frm_intr_stat , frm_stat ) ;
dev_err ( ctrl - > dev , " TX Nack FRM:cfg:0x%x, ie:0x%x \n " ,
frm_cfg , frm_ie_stat ) ;
dev_err ( ctrl - > dev , " TX Nack INTF:intr:0x%x, stat:0x%x \n " ,
intf_intr_stat , intf_stat ) ;
dev_err ( ctrl - > dev , " TX Nack INTF:ie:0x%x \n " ,
intf_ie_stat ) ;
err = - ENOTCONN ;
}
slim_ack_txn ( ctrl , err ) ;
return IRQ_HANDLED ;
}
static irqreturn_t qcom_slim_handle_rx_irq ( struct qcom_slim_ctrl * ctrl ,
u32 stat )
{
u32 * rx_buf , pkt [ 10 ] ;
bool q_rx = false ;
u8 mc , mt , len ;
pkt [ 0 ] = readl_relaxed ( ctrl - > base + MGR_RX_MSG ) ;
mt = SLIM_HEADER_GET_MT ( pkt [ 0 ] ) ;
len = SLIM_HEADER_GET_RL ( pkt [ 0 ] ) ;
mc = SLIM_HEADER_GET_MC ( pkt [ 0 ] > > 8 ) ;
/*
* this message cannot be handled by ISR , so
* let work - queue handle it
*/
if ( mt = = SLIM_MSG_MT_CORE & & mc = = SLIM_MSG_MC_REPORT_PRESENT ) {
rx_buf = ( u32 * ) slim_alloc_rxbuf ( ctrl ) ;
if ( ! rx_buf ) {
dev_err ( ctrl - > dev , " dropping RX:0x%x due to RX full \n " ,
pkt [ 0 ] ) ;
goto rx_ret_irq ;
}
rx_buf [ 0 ] = pkt [ 0 ] ;
} else {
rx_buf = pkt ;
}
__ioread32_copy ( rx_buf + 1 , ctrl - > base + MGR_RX_MSG + 4 ,
DIV_ROUND_UP ( len , 4 ) ) ;
switch ( mc ) {
case SLIM_MSG_MC_REPORT_PRESENT :
q_rx = true ;
break ;
case SLIM_MSG_MC_REPLY_INFORMATION :
case SLIM_MSG_MC_REPLY_VALUE :
slim_msg_response ( & ctrl - > ctrl , ( u8 * ) ( rx_buf + 1 ) ,
( u8 ) ( * rx_buf > > 24 ) , ( len - 4 ) ) ;
break ;
default :
dev_err ( ctrl - > dev , " unsupported MC,%x MT:%x \n " ,
mc , mt ) ;
break ;
}
rx_ret_irq :
writel ( MGR_INT_RX_MSG_RCVD , ctrl - > base +
MGR_INT_CLR ) ;
if ( q_rx )
queue_work ( ctrl - > rxwq , & ctrl - > wd ) ;
return IRQ_HANDLED ;
}
static irqreturn_t qcom_slim_interrupt ( int irq , void * d )
{
struct qcom_slim_ctrl * ctrl = d ;
u32 stat = readl_relaxed ( ctrl - > base + MGR_INT_STAT ) ;
int ret = IRQ_NONE ;
if ( stat & MGR_INT_TX_MSG_SENT | | stat & MGR_INT_TX_NACKED_2 )
ret = qcom_slim_handle_tx_irq ( ctrl , stat ) ;
if ( stat & MGR_INT_RX_MSG_RCVD )
ret = qcom_slim_handle_rx_irq ( ctrl , stat ) ;
return ret ;
}
2017-12-12 02:43:06 +03:00
static int qcom_clk_pause_wakeup ( struct slim_controller * sctrl )
{
struct qcom_slim_ctrl * ctrl = dev_get_drvdata ( sctrl - > dev ) ;
clk_prepare_enable ( ctrl - > hclk ) ;
clk_prepare_enable ( ctrl - > rclk ) ;
enable_irq ( ctrl - > irq ) ;
writel_relaxed ( 1 , ctrl - > base + FRM_WAKEUP ) ;
/* Make sure framer wakeup write goes through before ISR fires */
mb ( ) ;
/*
* HW Workaround : Currently , slave is reporting lost - sync messages
* after SLIMbus comes out of clock pause .
* Transaction with slave fail before slave reports that message
* Give some time for that report to come
* SLIMbus wakes up in clock gear 10 at 24.576 MHz . With each superframe
* being 250 usecs , we wait for 5 - 10 superframes here to ensure
* we get the message
*/
usleep_range ( 1250 , 2500 ) ;
return 0 ;
}
2018-01-02 20:54:21 +03:00
static void * slim_alloc_txbuf ( struct qcom_slim_ctrl * ctrl ,
struct slim_msg_txn * txn ,
struct completion * done )
2017-12-12 02:43:05 +03:00
{
unsigned long flags ;
int idx ;
spin_lock_irqsave ( & ctrl - > tx . lock , flags ) ;
if ( ( ( ctrl - > tx . head + 1 ) % ctrl - > tx . n ) = = ctrl - > tx . tail ) {
spin_unlock_irqrestore ( & ctrl - > tx . lock , flags ) ;
dev_err ( ctrl - > dev , " controller TX buf unavailable " ) ;
return NULL ;
}
idx = ctrl - > tx . tail ;
ctrl - > wr_comp [ idx ] = done ;
ctrl - > tx . tail = ( ctrl - > tx . tail + 1 ) % ctrl - > tx . n ;
spin_unlock_irqrestore ( & ctrl - > tx . lock , flags ) ;
return ctrl - > tx . base + ( idx * ctrl - > tx . sl_sz ) ;
}
static int qcom_xfer_msg ( struct slim_controller * sctrl ,
struct slim_msg_txn * txn )
{
struct qcom_slim_ctrl * ctrl = dev_get_drvdata ( sctrl - > dev ) ;
DECLARE_COMPLETION_ONSTACK ( done ) ;
void * pbuf = slim_alloc_txbuf ( ctrl , txn , & done ) ;
unsigned long ms = txn - > rl + HZ ;
u8 * puc ;
int ret = 0 , timeout , retries = QCOM_BUF_ALLOC_RETRIES ;
u8 la = txn - > la ;
u32 * head ;
/* HW expects length field to be excluded */
txn - > rl - - ;
/* spin till buffer is made available */
if ( ! pbuf ) {
while ( retries - - ) {
usleep_range ( 10000 , 15000 ) ;
pbuf = slim_alloc_txbuf ( ctrl , txn , & done ) ;
if ( pbuf )
break ;
}
}
2018-01-02 20:54:20 +03:00
if ( retries < 0 & & ! pbuf )
2017-12-12 02:43:05 +03:00
return - ENOMEM ;
puc = ( u8 * ) pbuf ;
head = ( u32 * ) pbuf ;
if ( txn - > dt = = SLIM_MSG_DEST_LOGICALADDR ) {
* head = SLIM_MSG_ASM_FIRST_WORD ( txn - > rl , txn - > mt ,
txn - > mc , 0 , la ) ;
puc + = 3 ;
} else {
* head = SLIM_MSG_ASM_FIRST_WORD ( txn - > rl , txn - > mt ,
txn - > mc , 1 , la ) ;
puc + = 2 ;
}
if ( slim_tid_txn ( txn - > mt , txn - > mc ) )
* ( puc + + ) = txn - > tid ;
if ( slim_ec_txn ( txn - > mt , txn - > mc ) ) {
* ( puc + + ) = ( txn - > ec & 0xFF ) ;
* ( puc + + ) = ( txn - > ec > > 8 ) & 0xFF ;
}
if ( txn - > msg & & txn - > msg - > wbuf )
memcpy ( puc , txn - > msg - > wbuf , txn - > msg - > num_bytes ) ;
qcom_slim_queue_tx ( ctrl , head , txn - > rl , MGR_TX_MSG ) ;
timeout = wait_for_completion_timeout ( & done , msecs_to_jiffies ( ms ) ) ;
if ( ! timeout ) {
dev_err ( ctrl - > dev , " TX timed out:MC:0x%x,mt:0x%x " , txn - > mc ,
txn - > mt ) ;
ret = - ETIMEDOUT ;
}
return ret ;
}
static int qcom_set_laddr ( struct slim_controller * sctrl ,
struct slim_eaddr * ead , u8 laddr )
{
struct qcom_slim_ctrl * ctrl = dev_get_drvdata ( sctrl - > dev ) ;
struct {
__be16 manf_id ;
__be16 prod_code ;
u8 dev_index ;
u8 instance ;
u8 laddr ;
} __packed p ;
struct slim_val_inf msg = { 0 } ;
DEFINE_SLIM_EDEST_TXN ( txn , SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS ,
10 , laddr , & msg ) ;
int ret ;
p . manf_id = cpu_to_be16 ( ead - > manf_id ) ;
p . prod_code = cpu_to_be16 ( ead - > prod_code ) ;
p . dev_index = ead - > dev_index ;
p . instance = ead - > instance ;
p . laddr = laddr ;
msg . wbuf = ( void * ) & p ;
msg . num_bytes = 7 ;
ret = slim_do_transfer ( & ctrl - > ctrl , & txn ) ;
if ( ret )
dev_err ( ctrl - > dev , " set LA:0x%x failed:ret:%d \n " ,
laddr , ret ) ;
return ret ;
}
static int slim_get_current_rxbuf ( struct qcom_slim_ctrl * ctrl , void * buf )
{
unsigned long flags ;
spin_lock_irqsave ( & ctrl - > rx . lock , flags ) ;
if ( ctrl - > rx . tail = = ctrl - > rx . head ) {
spin_unlock_irqrestore ( & ctrl - > rx . lock , flags ) ;
return - ENODATA ;
}
memcpy ( buf , ctrl - > rx . base + ( ctrl - > rx . head * ctrl - > rx . sl_sz ) ,
ctrl - > rx . sl_sz ) ;
ctrl - > rx . head = ( ctrl - > rx . head + 1 ) % ctrl - > rx . n ;
spin_unlock_irqrestore ( & ctrl - > rx . lock , flags ) ;
return 0 ;
}
static void qcom_slim_rxwq ( struct work_struct * work )
{
u8 buf [ SLIM_MSGQ_BUF_LEN ] ;
2018-05-11 14:17:44 +03:00
u8 mc , mt ;
2017-12-12 02:43:05 +03:00
int ret ;
struct qcom_slim_ctrl * ctrl = container_of ( work , struct qcom_slim_ctrl ,
wd ) ;
while ( ( slim_get_current_rxbuf ( ctrl , buf ) ) ! = - ENODATA ) {
mt = SLIM_HEADER_GET_MT ( buf [ 0 ] ) ;
mc = SLIM_HEADER_GET_MC ( buf [ 1 ] ) ;
if ( mt = = SLIM_MSG_MT_CORE & &
mc = = SLIM_MSG_MC_REPORT_PRESENT ) {
struct slim_eaddr ea ;
u8 laddr ;
ea . manf_id = be16_to_cpup ( ( __be16 * ) & buf [ 2 ] ) ;
ea . prod_code = be16_to_cpup ( ( __be16 * ) & buf [ 4 ] ) ;
ea . dev_index = buf [ 6 ] ;
ea . instance = buf [ 7 ] ;
ret = slim_device_report_present ( & ctrl - > ctrl , & ea ,
& laddr ) ;
if ( ret < 0 )
dev_err ( ctrl - > dev , " assign laddr failed:%d \n " ,
ret ) ;
} else {
dev_err ( ctrl - > dev , " unexpected message:mc:%x, mt:%x \n " ,
mc , mt ) ;
}
}
}
static void qcom_slim_prg_slew ( struct platform_device * pdev ,
struct qcom_slim_ctrl * ctrl )
{
struct resource * slew_mem ;
if ( ! ctrl - > slew_reg ) {
/* SLEW RATE register for this SLIMbus */
slew_mem = platform_get_resource_byname ( pdev , IORESOURCE_MEM ,
" slew " ) ;
ctrl - > slew_reg = devm_ioremap ( & pdev - > dev , slew_mem - > start ,
resource_size ( slew_mem ) ) ;
if ( ! ctrl - > slew_reg )
return ;
}
writel_relaxed ( 1 , ctrl - > slew_reg ) ;
/* Make sure SLIMbus-slew rate enabling goes through */
wmb ( ) ;
}
static int qcom_slim_probe ( struct platform_device * pdev )
{
struct qcom_slim_ctrl * ctrl ;
struct slim_controller * sctrl ;
struct resource * slim_mem ;
int ret , ver ;
ctrl = devm_kzalloc ( & pdev - > dev , sizeof ( * ctrl ) , GFP_KERNEL ) ;
if ( ! ctrl )
return - ENOMEM ;
ctrl - > hclk = devm_clk_get ( & pdev - > dev , " iface " ) ;
if ( IS_ERR ( ctrl - > hclk ) )
return PTR_ERR ( ctrl - > hclk ) ;
ctrl - > rclk = devm_clk_get ( & pdev - > dev , " core " ) ;
if ( IS_ERR ( ctrl - > rclk ) )
return PTR_ERR ( ctrl - > rclk ) ;
ret = clk_set_rate ( ctrl - > rclk , SLIM_ROOT_FREQ ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " ref-clock set-rate failed:%d \n " , ret ) ;
return ret ;
}
ctrl - > irq = platform_get_irq ( pdev , 0 ) ;
if ( ! ctrl - > irq ) {
dev_err ( & pdev - > dev , " no slimbus IRQ \n " ) ;
return - ENODEV ;
}
sctrl = & ctrl - > ctrl ;
sctrl - > dev = & pdev - > dev ;
ctrl - > dev = & pdev - > dev ;
platform_set_drvdata ( pdev , ctrl ) ;
dev_set_drvdata ( ctrl - > dev , ctrl ) ;
slim_mem = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " ctrl " ) ;
ctrl - > base = devm_ioremap_resource ( ctrl - > dev , slim_mem ) ;
2018-01-02 20:54:24 +03:00
if ( IS_ERR ( ctrl - > base ) ) {
2017-12-12 02:43:05 +03:00
dev_err ( & pdev - > dev , " IOremap failed \n " ) ;
2018-01-02 20:54:24 +03:00
return PTR_ERR ( ctrl - > base ) ;
2017-12-12 02:43:05 +03:00
}
sctrl - > set_laddr = qcom_set_laddr ;
sctrl - > xfer_msg = qcom_xfer_msg ;
2017-12-12 02:43:06 +03:00
sctrl - > wakeup = qcom_clk_pause_wakeup ;
2017-12-12 02:43:05 +03:00
ctrl - > tx . n = QCOM_TX_MSGS ;
ctrl - > tx . sl_sz = SLIM_MSGQ_BUF_LEN ;
ctrl - > rx . n = QCOM_RX_MSGS ;
ctrl - > rx . sl_sz = SLIM_MSGQ_BUF_LEN ;
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:03:40 +03:00
ctrl - > wr_comp = kcalloc ( QCOM_TX_MSGS , sizeof ( struct completion * ) ,
2017-12-12 02:43:05 +03:00
GFP_KERNEL ) ;
if ( ! ctrl - > wr_comp )
return - ENOMEM ;
spin_lock_init ( & ctrl - > rx . lock ) ;
spin_lock_init ( & ctrl - > tx . lock ) ;
INIT_WORK ( & ctrl - > wd , qcom_slim_rxwq ) ;
ctrl - > rxwq = create_singlethread_workqueue ( " qcom_slim_rx " ) ;
if ( ! ctrl - > rxwq ) {
dev_err ( ctrl - > dev , " Failed to start Rx WQ \n " ) ;
return - ENOMEM ;
}
ctrl - > framer . rootfreq = SLIM_ROOT_FREQ / 8 ;
ctrl - > framer . superfreq =
ctrl - > framer . rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8 ;
sctrl - > a_framer = & ctrl - > framer ;
sctrl - > clkgear = SLIM_MAX_CLK_GEAR ;
qcom_slim_prg_slew ( pdev , ctrl ) ;
ret = devm_request_irq ( & pdev - > dev , ctrl - > irq , qcom_slim_interrupt ,
IRQF_TRIGGER_HIGH , " qcom_slim_irq " , ctrl ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " request IRQ failed \n " ) ;
goto err_request_irq_failed ;
}
ret = clk_prepare_enable ( ctrl - > hclk ) ;
if ( ret )
goto err_hclk_enable_failed ;
ret = clk_prepare_enable ( ctrl - > rclk ) ;
if ( ret )
goto err_rclk_enable_failed ;
2018-01-02 13:48:54 +03:00
ctrl - > tx . base = devm_kcalloc ( & pdev - > dev , ctrl - > tx . n , ctrl - > tx . sl_sz ,
GFP_KERNEL ) ;
2017-12-12 02:43:05 +03:00
if ( ! ctrl - > tx . base ) {
ret = - ENOMEM ;
goto err ;
}
2018-01-02 13:48:54 +03:00
ctrl - > rx . base = devm_kcalloc ( & pdev - > dev , ctrl - > rx . n , ctrl - > rx . sl_sz ,
GFP_KERNEL ) ;
2017-12-12 02:43:05 +03:00
if ( ! ctrl - > rx . base ) {
ret = - ENOMEM ;
goto err ;
}
/* Register with framework before enabling frame, clock */
ret = slim_register_controller ( & ctrl - > ctrl ) ;
if ( ret ) {
dev_err ( ctrl - > dev , " error adding controller \n " ) ;
goto err ;
}
ver = readl_relaxed ( ctrl - > base ) ;
/* Version info in 16 MSbits */
ver > > = 16 ;
/* Component register initialization */
writel ( 1 , ctrl - > base + CFG_PORT ( COMP_CFG , ver ) ) ;
writel ( ( EE_MGR_RSC_GRP | EE_NGD_2 | EE_NGD_1 ) ,
ctrl - > base + CFG_PORT ( COMP_TRUST_CFG , ver ) ) ;
writel ( ( MGR_INT_TX_NACKED_2 |
MGR_INT_MSG_BUF_CONTE | MGR_INT_RX_MSG_RCVD |
MGR_INT_TX_MSG_SENT ) , ctrl - > base + MGR_INT_EN ) ;
writel ( 1 , ctrl - > base + MGR_CFG ) ;
/* Framer register initialization */
writel ( ( 1 < < INTR_WAKE ) | ( 0xA < < REF_CLK_GEAR ) |
( 0xA < < CLK_GEAR ) | ( 1 < < ROOT_FREQ ) | ( 1 < < FRM_ACTIVE ) | 1 ,
ctrl - > base + FRM_CFG ) ;
writel ( MGR_CFG_ENABLE , ctrl - > base + MGR_CFG ) ;
writel ( 1 , ctrl - > base + INTF_CFG ) ;
writel ( 1 , ctrl - > base + CFG_PORT ( COMP_CFG , ver ) ) ;
pm_runtime_use_autosuspend ( & pdev - > dev ) ;
pm_runtime_set_autosuspend_delay ( & pdev - > dev , QCOM_SLIM_AUTOSUSPEND ) ;
pm_runtime_set_active ( & pdev - > dev ) ;
pm_runtime_mark_last_busy ( & pdev - > dev ) ;
pm_runtime_enable ( & pdev - > dev ) ;
dev_dbg ( ctrl - > dev , " QCOM SB controller is up:ver:0x%x! \n " , ver ) ;
return 0 ;
err :
clk_disable_unprepare ( ctrl - > rclk ) ;
err_rclk_enable_failed :
clk_disable_unprepare ( ctrl - > hclk ) ;
err_hclk_enable_failed :
err_request_irq_failed :
destroy_workqueue ( ctrl - > rxwq ) ;
return ret ;
}
static int qcom_slim_remove ( struct platform_device * pdev )
{
struct qcom_slim_ctrl * ctrl = platform_get_drvdata ( pdev ) ;
2017-12-12 02:43:06 +03:00
pm_runtime_disable ( & pdev - > dev ) ;
2017-12-12 02:43:05 +03:00
slim_unregister_controller ( & ctrl - > ctrl ) ;
destroy_workqueue ( ctrl - > rxwq ) ;
return 0 ;
}
2017-12-12 02:43:06 +03:00
/*
* If PM_RUNTIME is not defined , these 2 functions become helper
* functions to be called from system suspend / resume .
*/
# ifdef CONFIG_PM
static int qcom_slim_runtime_suspend ( struct device * device )
{
2018-11-30 14:57:41 +03:00
struct qcom_slim_ctrl * ctrl = dev_get_drvdata ( device ) ;
2017-12-12 02:43:06 +03:00
int ret ;
dev_dbg ( device , " pm_runtime: suspending... \n " ) ;
ret = slim_ctrl_clk_pause ( & ctrl - > ctrl , false , SLIM_CLK_UNSPECIFIED ) ;
if ( ret ) {
dev_err ( device , " clk pause not entered:%d " , ret ) ;
} else {
disable_irq ( ctrl - > irq ) ;
clk_disable_unprepare ( ctrl - > hclk ) ;
clk_disable_unprepare ( ctrl - > rclk ) ;
}
return ret ;
}
static int qcom_slim_runtime_resume ( struct device * device )
{
2018-11-30 14:57:41 +03:00
struct qcom_slim_ctrl * ctrl = dev_get_drvdata ( device ) ;
2017-12-12 02:43:06 +03:00
int ret = 0 ;
dev_dbg ( device , " pm_runtime: resuming... \n " ) ;
ret = slim_ctrl_clk_pause ( & ctrl - > ctrl , true , 0 ) ;
if ( ret )
dev_err ( device , " clk pause not exited:%d " , ret ) ;
return ret ;
}
# endif
# ifdef CONFIG_PM_SLEEP
static int qcom_slim_suspend ( struct device * dev )
{
int ret = 0 ;
if ( ! pm_runtime_enabled ( dev ) | |
( ! pm_runtime_suspended ( dev ) ) ) {
dev_dbg ( dev , " system suspend " ) ;
ret = qcom_slim_runtime_suspend ( dev ) ;
}
return ret ;
}
static int qcom_slim_resume ( struct device * dev )
{
if ( ! pm_runtime_enabled ( dev ) | | ! pm_runtime_suspended ( dev ) ) {
int ret ;
dev_dbg ( dev , " system resume " ) ;
ret = qcom_slim_runtime_resume ( dev ) ;
if ( ! ret ) {
pm_runtime_mark_last_busy ( dev ) ;
pm_request_autosuspend ( dev ) ;
}
return ret ;
}
return 0 ;
}
# endif /* CONFIG_PM_SLEEP */
2017-12-12 02:43:05 +03:00
static const struct dev_pm_ops qcom_slim_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( qcom_slim_suspend , qcom_slim_resume )
SET_RUNTIME_PM_OPS (
qcom_slim_runtime_suspend ,
qcom_slim_runtime_resume ,
NULL
)
} ;
static const struct of_device_id qcom_slim_dt_match [ ] = {
{ . compatible = " qcom,slim " , } ,
{ . compatible = " qcom,apq8064-slim " , } ,
{ }
} ;
static struct platform_driver qcom_slim_driver = {
. probe = qcom_slim_probe ,
. remove = qcom_slim_remove ,
. driver = {
. name = " qcom_slim_ctrl " ,
. of_match_table = qcom_slim_dt_match ,
2017-12-12 02:43:06 +03:00
. pm = & qcom_slim_dev_pm_ops ,
2017-12-12 02:43:05 +03:00
} ,
} ;
module_platform_driver ( qcom_slim_driver ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " Qualcomm SLIMbus Controller " ) ;