@@ -145,45 +145,60 @@ static int mcp25xxfd_write_then_read(struct spi_device *spi,
145145{
146146 struct mcp25xxfd_priv * priv = spi_get_drvdata (spi );
147147 struct spi_transfer xfer [2 ];
148- u8 single_reg_data_tx [ 6 ] ;
149- u8 single_reg_data_rx [ 6 ] ;
148+ u8 * spi_tx , * spi_rx ;
149+ int xfers ;
150150 int ret ;
151151
152+ /* use allocated buffer when too big or already in use */
153+ if ((tx_len + rx_len > MCP25XXFD_BUFFER_TXRX_SIZE ) ||
154+ !spin_trylock (& priv -> spi_rxtx_lock )) {
155+ spi_tx = kzalloc (2 * (tx_len + rx_len ), GFP_KERNEL );
156+ spi_rx = spi_tx + tx_len + rx_len ;
157+ } else {
158+ spi_tx = priv -> spi_tx ;
159+ spi_rx = priv -> spi_rx ;
160+ }
161+
162+ /* clear the xfers */
152163 memset (xfer , 0 , sizeof (xfer ));
153164
154- /* when using a halfduplex controller or to big for buffer */
165+ /* when using a halfduplex controller still copy the buffers to
166+ * avoid stack objects
167+ */
155168 if ((spi -> master -> flags & SPI_MASTER_HALF_DUPLEX ) ||
156169 (tx_len + rx_len > sizeof (priv -> spi_tx ))) {
157- xfer [0 ].tx_buf = tx_buf ;
170+ xfers = 2 ;
171+ xfer [0 ].tx_buf = priv -> spi_tx ;
158172 xfer [0 ].len = tx_len ;
159173
160- xfer [1 ].rx_buf = rx_buf ;
174+ xfer [1 ].rx_buf = priv -> spi_rx + tx_len ;
161175 xfer [1 ].len = rx_len ;
162-
163- return mcp25xxfd_sync_transfer (spi , xfer , 2 );
164- }
165-
166- /* full duplex optimization */
167- xfer [0 ].len = tx_len + rx_len ;
168- if (xfer [0 ].len > sizeof (single_reg_data_tx )) {
169- mutex_lock (& priv -> spi_rxtx_lock );
176+ } else {
177+ xfers = 1 ;
178+ xfer [0 ].len = tx_len + rx_len ;
170179 xfer [0 ].tx_buf = priv -> spi_tx ;
171180 xfer [0 ].rx_buf = priv -> spi_rx ;
172- } else {
173- xfer [ 0 ]. tx_buf = single_reg_data_tx ;
174- xfer [0 ].rx_buf = single_reg_data_rx ;
181+
182+ /* clean the data after the write block */
183+ memset (( u8 * ) xfer [0 ].tx_buf + tx_len , 0 , rx_len ) ;
175184 }
176185
177- /* copy and clean */
186+ /* copy especially to avoid buffers from stack */
178187 memcpy ((u8 * )xfer [0 ].tx_buf , tx_buf , tx_len );
179- memset ((u8 * )xfer [0 ].tx_buf + tx_len , 0 , rx_len );
180188
181- ret = mcp25xxfd_sync_transfer (spi , xfer , 1 );
182- if (!ret )
183- memcpy (rx_buf , xfer [0 ].rx_buf + tx_len , rx_len );
189+ /* do the transfer */
190+ ret = mcp25xxfd_sync_transfer (spi , xfer , xfers );
191+ if (ret )
192+ goto out ;
193+
194+ /* copy result back */
195+ memcpy (rx_buf , xfer [0 ].rx_buf + tx_len , rx_len );
184196
185- if (xfer [0 ].len > sizeof (single_reg_data_tx ))
186- mutex_unlock (& priv -> spi_rxtx_lock );
197+ out :
198+ if (spi_tx == priv -> spi_tx )
199+ spin_unlock (& priv -> spi_rxtx_lock );
200+ else
201+ kfree (spi_tx );
187202
188203 return ret ;
189204}
@@ -196,29 +211,33 @@ static int mcp25xxfd_write_then_write(struct spi_device *spi,
196211{
197212 struct mcp25xxfd_priv * priv = spi_get_drvdata (spi );
198213 struct spi_transfer xfer ;
199- u8 single_reg_data [6 ];
200214 int ret ;
201215
202- if (tx_len + tx2_len > MCP25XXFD_BUFFER_TXRX_SIZE )
203- return - EINVAL ;
204-
216+ /* clear the xfers */
205217 memset (& xfer , 0 , sizeof (xfer ));
206-
207218 xfer .len = tx_len + tx2_len ;
208- if (xfer .len > sizeof (single_reg_data )) {
209- mutex_lock (& priv -> spi_rxtx_lock );
210- xfer .tx_buf = priv -> spi_tx ;
219+ xfer .tx_buf = priv -> spi_tx ;
220+
221+ /* use allocated buffer when too big or already in use */
222+ if ((tx_len + tx2_len > MCP25XXFD_BUFFER_TXRX_SIZE ) ||
223+ !spin_trylock (& priv -> spi_rxtx_lock )) {
224+ xfer .tx_buf = kzalloc (tx_len + tx2_len , GFP_KERNEL );
211225 } else {
212- xfer .tx_buf = single_reg_data ;
226+ xfer .tx_buf = priv -> spi_tx ;
213227 }
214228
229+ /* copy data to location */
215230 memcpy ((u8 * )xfer .tx_buf , tx_buf , tx_len );
216231 memcpy ((u8 * )xfer .tx_buf + tx_len , tx2_buf , tx2_len );
217232
233+ /* run the transfer */
218234 ret = mcp25xxfd_sync_transfer (spi , & xfer , 1 );
219235
220- if (xfer .len > sizeof (single_reg_data ))
221- mutex_unlock (& priv -> spi_rxtx_lock );
236+ /* release lock */
237+ if (xfer .tx_buf == priv -> spi_tx )
238+ spin_unlock (& priv -> spi_rxtx_lock );
239+ else
240+ kfree (xfer .tx_buf );
222241
223242 return ret ;
224243}
@@ -978,8 +997,10 @@ static int mcp25xxfd_probe(struct spi_device *spi)
978997
979998 spi_set_drvdata (spi , priv );
980999 priv -> spi = spi ;
1000+ priv -> clk = clk ;
9811001
9821002 mutex_init (& priv -> clk_user_lock );
1003+ spin_lock_init (& priv -> spi_rxtx_lock );
9831004
9841005 /* enable the clock and mark as enabled */
9851006 ret = clk_prepare_enable (clk );
0 commit comments