From: Wolfram Sang <hidden> Date: 2015-01-09 17:22:23
Recently, a number of submitted I2C master drivers could not fully handle all
I2C type transfers due to limited HW. So, they had to bail out with some errno
although the user supplied a valid I2C transfer. In order to centralize such
quirks, a central structure describing the quirks is introduced. The next patch
lets the core do the checks based on the information about the quirks. Then
existing drivers with quirks are converted.
This already has the advantage of avoiding code duplication and having
consistent error handling. Later, once the structure is tested and stable, we
can pass it over to the users, so they can actually check what the current HW
is capable of and react accordingly.
These patches are RFC and only build-tested so far. Yet, I wanted to show what
I am up to. I will do some testing on HW once I finished my task of fixing the
slave interface, hopefully after next week.
I'd really love to see this go into v3.20, but this will need assistance. I
really need testers, at least for the recent hardware. Other comments/reviews
are also appreciated.
Patches are based on v3.19-rc3 and the branch is here
git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/quirks
Thanks,
Wolfram
Wolfram Sang (11):
i2c: add quirk structure to describe adapter flaws
i2c: add quirk checks to core
i2c: at91: make use of the new infrastructure for quirks
i2c: opal: make use of the new infrastructure for quirks
i2c: qup: make use of the new infrastructure for quirks
i2c: cpm: make use of the new infrastructure for quirks
i2c: axxia: make use of the new infrastructure for quirks
i2c: dln2: make use of the new infrastructure for quirks
i2c: powermac: make use of the new infrastructure for quirks
i2c: viperboard: make use of the new infrastructure for quirks
i2c: pmcmsp: make use of the new infrastructure for quirks
drivers/i2c/busses/i2c-at91.c | 32 ++++++++--------------
drivers/i2c/busses/i2c-axxia.c | 11 ++++----
drivers/i2c/busses/i2c-cpm.c | 20 +++++++-------
drivers/i2c/busses/i2c-dln2.c | 12 ++++-----
drivers/i2c/busses/i2c-opal.c | 22 +++++++--------
drivers/i2c/busses/i2c-pmcmsp.c | 42 +++++++++++------------------
drivers/i2c/busses/i2c-powermac.c | 10 +++----
drivers/i2c/busses/i2c-qup.c | 21 +++++++--------
drivers/i2c/busses/i2c-viperboard.c | 10 ++++---
drivers/i2c/i2c-core.c | 53 +++++++++++++++++++++++++++++++++++++
include/linux/i2c.h | 35 ++++++++++++++++++++++++
11 files changed, 167 insertions(+), 101 deletions(-)
--
2.1.3
From: Wolfram Sang <hidden> Date: 2015-01-09 17:22:21
The number of I2C adapters which are not fully I2C compatible is rising,
sadly. Drivers usually do handle the flaws, still the user receives only
some errno for a transfer which normally can be expected to work. This
patch introduces a formal description of flaws. One advantage is that
the core can check before the actual transfer if the messages could be
transferred at all. This is done in the next patch. Another advantage is
that we can pass this information to the user so the restrictions are
exactly known and further actions can be based on that. This will be
done later after some stabilization period for this description.
Signed-off-by: Wolfram Sang <redacted>
---
include/linux/i2c.h | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
I suggest to add const.
const struct i2c_adapter_quirks *quirks;
also, in i2c-core.c, should modify:
const struct i2c_adapter_quirks *q = adap->quirks;
I suggest to add const.
const struct i2c_adapter_quirks *quirks;
also, in i2c-core.c, should modify:
const struct i2c_adapter_quirks *q = adap->quirks;
I suggest to add const.
const struct i2c_adapter_quirks *quirks;
also, in i2c-core.c, should modify:
const struct i2c_adapter_quirks *q = adap->quirks;
On Fri, 2015-01-09 at 18:21 +0100, Wolfram Sang wrote:
The number of I2C adapters which are not fully I2C compatible is rising,
sadly. Drivers usually do handle the flaws, still the user receives only
some errno for a transfer which normally can be expected to work. This
patch introduces a formal description of flaws. One advantage is that
the core can check before the actual transfer if the messages could be
transferred at all. This is done in the next patch. Another advantage is
that we can pass this information to the user so the restrictions are
exactly known and further actions can be based on that. This will be
done later after some stabilization period for this description.
Hi Wolfram,
This can describe the behavior of our current upstream driver[1], which
only support combine write-then-read.
After checking with Xudong & HW guys, it seems our HW can do more.
On MT8135, it can support at most 2 messages, no matter read or write,
with the limitation that the length of the second message must <=
31bytes.
So this RFC is enough for our driver, but it would be better if we could
also support other case.
Joe.C
[1]:
http://lists.infradead.org/pipermail/linux-arm-kernel/2014-November/305468.html
From: Wolfram Sang <hidden> Date: 2015-01-19 15:00:27
Hi,
This can describe the behavior of our current upstream driver[1], which
only support combine write-then-read.
After checking with Xudong & HW guys, it seems our HW can do more.
On MT8135, it can support at most 2 messages, no matter read or write,
with the limitation that the length of the second message must <=
31bytes.
So this RFC is enough for our driver, but it would be better if we could
also support other case.
Hmm, I think we can convert max_comb_{read|write}_len to
max_comb_{1st|2nd}_msg_len or similar.
I'll check but it will probably not before next week.
Thanks for the input!
@@ -308,22 +308,12 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)structi2c_reg__iomem*i2c_reg=cpm->i2c_reg;structi2c_ram__iomem*i2c_ram=cpm->i2c_ram;structi2c_msg*pmsg;-intret,i;+intret;inttptr;intrptr;cbd_t__iomem*tbdf;cbd_t__iomem*rbdf;-if(num>CPM_MAXBD)-return-EINVAL;--/* Check if we have any oversized READ requests */-for(i=0;i<num;i++){-pmsg=&msgs[i];-if(pmsg->len>=CPM_MAX_READ)-return-EINVAL;-}-/* Reset to use first buffer */out_be16(&i2c_ram->rbptr,in_be16(&i2c_ram->rbase));out_be16(&i2c_ram->tbptr,in_be16(&i2c_ram->tbase));
@@ -424,10 +414,18 @@ static const struct i2c_algorithm cpm_i2c_algo = {.functionality=cpm_i2c_func,};+/* CPM_MAX_READ is also limiting writes according to the code! */+staticstructi2c_adapter_quirkscpm_i2c_quirks={+.max_num_msgs=CPM_MAXBD,+.max_read_len=CPM_MAX_READ,+.max_write_len=CPM_MAX_READ,+};+staticconststructi2c_adaptercpm_ops={.owner=THIS_MODULE,.name="i2c-cpm",.algo=&cpm_i2c_algo,+.quirks=&cpm_i2c_quirks,};staticintcpm_i2c_setup(structcpm_i2c*cpm)
@@ -288,10 +288,6 @@ static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs,i,pmsg->flags&I2C_M_RD?"read":"write",pmsg->flags,pmsg->len,pmsg->addr);-/* msgs longer than 2048 bytes are not supported by adapter */-if(pmsg->len>2048)-return-EINVAL;-mutex_lock(&vb->lock);/* directly send the message */if(pmsg->flags&I2C_M_RD){
@@ -373,6 +374,7 @@ static int vprbrd_i2c_probe(struct platform_device *pdev)vb_i2c->i2c.owner=THIS_MODULE;vb_i2c->i2c.class=I2C_CLASS_HWMON;vb_i2c->i2c.algo=&vprbrd_algorithm;+vb_i2c->i2c.quirks=&vprbrd_quirks;vb_i2c->i2c.algo_data=vb;/* save the param in usb capabable memory */vb_i2c->bus_freq_param=i2c_bus_param;
@@ -463,14 +463,6 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(return-EINVAL;}-if(cmd->read_len>MSP_MAX_BYTES_PER_RW||-cmd->write_len>MSP_MAX_BYTES_PER_RW){-dev_err(&pmcmsptwi_adapter.dev,-"%s: Cannot transfer more than %d bytes\n",-__func__,MSP_MAX_BYTES_PER_RW);-return-EINVAL;-}-mutex_lock(&data->lock);dev_dbg(&pmcmsptwi_adapter.dev,"Setting address to 0x%04x\n",cmd->addr);
@@ -527,25 +519,14 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,structpmcmsptwi_cfgoldcfg,newcfg;intret;-if(num>2){-dev_dbg(&adap->dev,"%d messages unsupported\n",num);-return-EINVAL;-}elseif(num==2){-/* Check for a dual write-then-read command */+if(num==2){structi2c_msg*nextmsg=msg+1;-if(!(msg->flags&I2C_M_RD)&&-(nextmsg->flags&I2C_M_RD)&&-msg->addr==nextmsg->addr){-cmd.type=MSP_TWI_CMD_WRITE_READ;-cmd.write_len=msg->len;-cmd.write_data=msg->buf;-cmd.read_len=nextmsg->len;-cmd.read_data=nextmsg->buf;-}else{-dev_dbg(&adap->dev,-"Non write-read dual messages unsupported\n");-return-EINVAL;-}++cmd.type=MSP_TWI_CMD_WRITE_READ;+cmd.write_len=msg->len;+cmd.write_data=msg->buf;+cmd.read_len=nextmsg->len;+cmd.read_data=nextmsg->buf;}elseif(msg->flags&I2C_M_RD){cmd.type=MSP_TWI_CMD_READ;cmd.read_len=msg->len;
@@ -412,17 +412,6 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)unsignedlongleft;intret;-/*-*TheQUPblockwillissueaNACKandSTOPonthebuswhenreaching-*theendoftheread,thelengthofthereadisspecifiedasonebyte-*whichlimitsthepossiblereadto256(QUP_READ_LIMIT)bytes.-*/-if(msg->len>QUP_READ_LIMIT){-dev_err(qup->dev,"HW not capable of reads over %d bytes\n",-QUP_READ_LIMIT);-return-EINVAL;-}-qup->msg=msg;qup->pos=0;
@@ -104,17 +104,6 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,req.buffer_ra=cpu_to_be64(__pa(msgs[0].buf));break;case2:-/* For two messages, we basically support only simple-*smbustransactionsofawriteplusaread.Wemight-*wanttoallowalsotwowritesbutwe'dhavetobounce-*thedataintoasinglebuffer.-*/-if((msgs[0].flags&I2C_M_RD)||!(msgs[1].flags&I2C_M_RD))-return-EOPNOTSUPP;-if(msgs[0].len>4)-return-EOPNOTSUPP;-if(msgs[0].addr!=msgs[1].addr)-return-EOPNOTSUPP;req.type=OPAL_I2C_SM_READ;req.addr=cpu_to_be16(msgs[0].addr);req.subaddr_sz=msgs[0].len;
@@ -210,6 +199,16 @@ static const struct i2c_algorithm i2c_opal_algo = {.functionality=i2c_opal_func,};+/* For two messages, we basically support only simple+*smbustransactionsofawriteplusaread.Wemight+*wanttoallowalsotwowritesbutwe'dhavetobounce+*thedataintoasinglebuffer.+*/+staticstructi2c_adapter_quirksi2c_opal_quirks={+.flags=I2C_ADAPTER_QUIRK_COMB_WRITE_THEN_READ,+.max_comb_write_len=4,+};+staticinti2c_opal_probe(structplatform_device*pdev){structi2c_adapter*adapter;
@@ -232,6 +231,7 @@ static int i2c_opal_probe(struct platform_device *pdev)adapter->algo=&i2c_opal_algo;adapter->algo_data=(void*)(unsignedlong)opal_id;+adapter->quirks=&i2c_opal_quirks;adapter->dev.parent=&pdev->dev;adapter->dev.of_node=of_node_get(pdev->dev.of_node);pname=of_get_property(pdev->dev.of_node,"ibm,port-name",NULL);
@@ -487,30 +487,10 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)if(ret<0)gotoout;-/*-*Thehardwarecanhandleatmosttwomessagesconcatenatedbya-*repeatedstartviait'sinternaladdressfeature.-*/-if(num>2){-dev_err(dev->dev,-"cannot handle more than two concatenated messages.\n");-ret=0;-gotoout;-}elseif(num==2){+if(num==2){intinternal_address=0;inti;-if(msg->flags&I2C_M_RD){-dev_err(dev->dev,"first transfer must be write.\n");-ret=-EINVAL;-gotoout;-}-if(msg->len>3){-dev_err(dev->dev,"first message size must be <= 3.\n");-ret=-EINVAL;-gotoout;-}-/* 1st msg is put into the internal address, start with 2nd */m_start=&msg[1];for(i=0;i<msg->len;++i){
From: Wolfram Sang <hidden> Date: 2015-01-09 17:26:54
Let the core do the checks if HW quirks prevent a transfer. Saves code
from drivers and adds consistency.
Signed-off-by: Wolfram Sang <redacted>
---
drivers/i2c/i2c-core.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
@@ -2063,6 +2063,56 @@ module_exit(i2c_exit);*----------------------------------------------------*/+/* Check if val is exceeding the quirk IFF quirk is non 0 */+#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))++staticinti2c_quirk_error(structi2c_adapter*adap,structi2c_msg*msg,char*err_msg)+{+dev_err(&adap->dev,"quirk: %s (addr 0x%04x, size %u)\n",err_msg,msg->addr,msg->len);+return-EOPNOTSUPP;+}++staticinti2c_check_for_quirks(structi2c_adapter*adap,structi2c_msg*msgs,intnum)+{+structi2c_adapter_quirks*q=adap->quirks;+u16max_read=q->max_read_len,max_write=q->max_write_len;+intmax_num=q->max_num_msgs,i;++if(q->flags&I2C_ADAPTER_QUIRK_COMB_WRITE_THEN_READ)+max_num=2;++if(i2c_quirk_exceeded(num,max_num))+returni2c_quirk_error(adap,&msgs[0],"too many messages");++if(num==2&&q->flags&I2C_ADAPTER_QUIRK_COMB_WRITE_FIRST){+if(msgs[0].flags&I2C_M_RD)+returni2c_quirk_error(adap,&msgs[0],"invalid first write msg");++max_write=q->max_comb_write_len;+}++if(num==2&&q->flags&I2C_ADAPTER_QUIRK_COMB_READ_SECOND){+if(!(msgs[1].flags&I2C_M_RD)||msgs[0].addr!=msgs[1].addr)+returni2c_quirk_error(adap,&msgs[1],"invalid second read msg");++max_read=q->max_comb_read_len;+}++for(i=0;i<num;i++){+u16len=msgs[i].len;++if(msgs[i].flags&I2C_M_RD){+if(i2c_quirk_exceeded(len,max_read))+returni2c_quirk_error(adap,&msgs[i],"msg too long");+}else{+if(i2c_quirk_exceeded(len,max_write))+returni2c_quirk_error(adap,&msgs[i],"msg too long");+}+}++return0;+}+/***__i2c_transfer-unlockedflavorofi2c_transfer*@adap:HandletoI2Cbus
@@ -2080,6 +2130,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)unsignedlongorig_jiffies;intret,try;+if(adap->quirks&&i2c_check_for_quirks(adap,msgs,num))+return-EOPNOTSUPP;+/* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets*enabled.Thisisanefficientwayofkeepingthefor-loopfrom*beingexecutedwhennotneeded.
@@ -2063,6 +2063,56 @@ module_exit(i2c_exit);*----------------------------------------------------*/+/* Check if val is exceeding the quirk IFF quirk is non 0 */+#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))++staticinti2c_quirk_error(structi2c_adapter*adap,structi2c_msg*msg,char*err_msg)+{+dev_err(&adap->dev,"quirk: %s (addr 0x%04x, size %u)\n",err_msg,msg->addr,msg->len);+return-EOPNOTSUPP;+}
Always returning the same value doesn't make much sense. Are you trying to
save space on the call sites?
[...]
quoted hunk
@@ -2080,6 +2130,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) unsigned long orig_jiffies; int ret, try;+ if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
So, you only check for non-zero result of this function? Perhaps it makes
sense to return true/false instead?
@@ -2063,6 +2063,56 @@ module_exit(i2c_exit);*----------------------------------------------------*/+/* Check if val is exceeding the quirk IFF quirk is non 0 */+#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))++staticinti2c_quirk_error(structi2c_adapter*adap,structi2c_msg*msg,char*err_msg)+{+dev_err(&adap->dev,"quirk: %s (addr 0x%04x, size %u)\n",err_msg,msg->addr,msg->len);+return-EOPNOTSUPP;+}
Always returning the same value doesn't make much sense. Are you trying
to save space on the call sites?
Please elaborate. I think it does. If a quirk matches, we report that we
don't support this transfer.
[...]
quoted
@@ -2080,6 +2130,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) unsigned long orig_jiffies; int ret, try;+ if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
So, you only check for non-zero result of this function? Perhaps it makes
sense to return true/false instead?
Could be done, but what would be the advantage? A lot of functions
return errno or 0.
@@ -2063,6 +2063,56 @@ module_exit(i2c_exit);*----------------------------------------------------*/+/* Check if val is exceeding the quirk IFF quirk is non 0 */+#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))++staticinti2c_quirk_error(structi2c_adapter*adap,structi2c_msg*msg,char*err_msg)+{+dev_err(&adap->dev,"quirk: %s (addr 0x%04x, size %u)\n",err_msg,msg->addr,msg->len);+return-EOPNOTSUPP;+}
quoted
Always returning the same value doesn't make much sense. Are you trying
to save space on the call sites?
Please elaborate. I think it does. If a quirk matches, we report that we
don't support this transfer.
OK, but what's the point of having this function return *int* if it always
returns the same value? AFAIU, you're trying to save the code space on the
call sites of this function by not having *return* -EOPNOTSUPP there each time?
quoted
[...]
quoted
@@ -2080,6 +2130,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) unsigned long orig_jiffies; int ret, try;+ if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))
quoted
So, you only check for non-zero result of this function? Perhaps it makes
sense to return true/false instead?
Could be done, but what would be the advantage? A lot of functions
return errno or 0.
It would have been OK if you were actually caring about the result, e.g.
returning it from __i2c_transfer(). Since you don't, IMO it would make more
sense to return true from i2c_check_for_quirks() (making it *bool*) iff it did
find/apply a quirk.
WBR, Sergei
Hi Wolfram,
On Fri, Jan 09, 2015 at 06:21:32PM +0100, Wolfram Sang wrote:
quoted hunk
Let the core do the checks if HW quirks prevent a transfer. Saves code
from drivers and adds consistency.
Signed-off-by: Wolfram Sang <redacted>
---
drivers/i2c/i2c-core.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
@@ -2063,6 +2063,56 @@ module_exit(i2c_exit);*----------------------------------------------------*/+/* Check if val is exceeding the quirk IFF quirk is non 0 */+#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))++staticinti2c_quirk_error(structi2c_adapter*adap,structi2c_msg*msg,char*err_msg)+{+dev_err(&adap->dev,"quirk: %s (addr 0x%04x, size %u)\n",err_msg,msg->addr,msg->len);+return-EOPNOTSUPP;+}++staticinti2c_check_for_quirks(structi2c_adapter*adap,structi2c_msg*msgs,intnum)+{+structi2c_adapter_quirks*q=adap->quirks;+u16max_read=q->max_read_len,max_write=q->max_write_len;+intmax_num=q->max_num_msgs,i;++if(q->flags&I2C_ADAPTER_QUIRK_COMB_WRITE_THEN_READ)+max_num=2;++if(i2c_quirk_exceeded(num,max_num))+returni2c_quirk_error(adap,&msgs[0],"too many messages");++if(num==2&&q->flags&I2C_ADAPTER_QUIRK_COMB_WRITE_FIRST){+if(msgs[0].flags&I2C_M_RD)+returni2c_quirk_error(adap,&msgs[0],"invalid first write msg");++max_write=q->max_comb_write_len;+}++if(num==2&&q->flags&I2C_ADAPTER_QUIRK_COMB_READ_SECOND){+if(!(msgs[1].flags&I2C_M_RD)||msgs[0].addr!=msgs[1].addr)+returni2c_quirk_error(adap,&msgs[1],"invalid second read msg");++max_read=q->max_comb_read_len;+}++for(i=0;i<num;i++){+u16len=msgs[i].len;++if(msgs[i].flags&I2C_M_RD){+if(i2c_quirk_exceeded(len,max_read))+returni2c_quirk_error(adap,&msgs[i],"msg too long");+}else{+if(i2c_quirk_exceeded(len,max_write))+returni2c_quirk_error(adap,&msgs[i],"msg too long");+}+}+
I am not sure it will perfectly fit at91 quirks.
The hardware can handle two messages by using the internal address
feature. The internal address size is from one byte to three bytes. Then
the length of the first message is limited to three but we don't have
this constraint for the second one. If we have 'write then read' no problem
but if we have two write messages, the second one will cause a quirk
exceeded error.
Regards
Ludovic
quoted hunk
+ return 0;
+}
+
/**
* __i2c_transfer - unlocked flavor of i2c_transfer
* @adap: Handle to I2C bus
@@ -2080,6 +2130,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) unsigned long orig_jiffies; int ret, try;+ if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))+ return -EOPNOTSUPP;+ /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets * enabled. This is an efficient way of keeping the for-loop from * being executed when not needed.
From: Wolfram Sang <hidden> Date: 2015-01-12 10:13:59
I am not sure it will perfectly fit at91 quirks.
I think it does.
The hardware can handle two messages by using the internal address
feature. The internal address size is from one byte to three bytes. Then
the length of the first message is limited to three but we don't have
this constraint for the second one. If we have 'write then read' no problem
but if we have two write messages, the second one will cause a quirk
exceeded error.
Yeah, for this reason I seperated I2C_ADAPTER_QUIRK_COMB_WRITE_FIRST
out. The first message is checked against max_comb_write_len which is
set to 3 for your driver. The second is checked agains max_write_len
which is unset in your driver and thus can be of any length.
That should work, no?
So, what happens if I open an I2C adapter, find a message which causes
i2c_quirk_error() to be called, and then spin repeatedly calling that...
Shouldn't there be some rate limiting to this?
--
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.
So, what happens if I open an I2C adapter, find a message which causes
i2c_quirk_error() to be called, and then spin repeatedly calling that...
Shouldn't there be some rate limiting to this?
Can be argued. Changed to dev_err_ratelimited(). Thanks!
2015-01-09 18:21 GMT+01:00 Wolfram Sang [off-list ref]:
quoted hunk
Let the core do the checks if HW quirks prevent a transfer. Saves code
from drivers and adds consistency.
Signed-off-by: Wolfram Sang <redacted>
---
drivers/i2c/i2c-core.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
@@ -2063,6 +2063,56 @@ module_exit(i2c_exit);*----------------------------------------------------*/+/* Check if val is exceeding the quirk IFF quirk is non 0 */+#define i2c_quirk_exceeded(val, quirk) ((quirk) && ((val) > (quirk)))++staticinti2c_quirk_error(structi2c_adapter*adap,structi2c_msg*msg,char*err_msg)+{+dev_err(&adap->dev,"quirk: %s (addr 0x%04x, size %u)\n",err_msg,msg->addr,msg->len);+return-EOPNOTSUPP;+}++staticinti2c_check_for_quirks(structi2c_adapter*adap,structi2c_msg*msgs,intnum)+{+structi2c_adapter_quirks*q=adap->quirks;+u16max_read=q->max_read_len,max_write=q->max_write_len;+intmax_num=q->max_num_msgs,i;++if(q->flags&I2C_ADAPTER_QUIRK_COMB_WRITE_THEN_READ)+max_num=2;++if(i2c_quirk_exceeded(num,max_num))+returni2c_quirk_error(adap,&msgs[0],"too many messages");++if(num==2&&q->flags&I2C_ADAPTER_QUIRK_COMB_WRITE_FIRST){+if(msgs[0].flags&I2C_M_RD)+returni2c_quirk_error(adap,&msgs[0],"invalid first write msg");++max_write=q->max_comb_write_len;+}++if(num==2&&q->flags&I2C_ADAPTER_QUIRK_COMB_READ_SECOND){+if(!(msgs[1].flags&I2C_M_RD)||msgs[0].addr!=msgs[1].addr)+returni2c_quirk_error(adap,&msgs[1],"invalid second read msg");++max_read=q->max_comb_read_len;+}++for(i=0;i<num;i++){+u16len=msgs[i].len;++if(msgs[i].flags&I2C_M_RD){+if(i2c_quirk_exceeded(len,max_read))+returni2c_quirk_error(adap,&msgs[i],"msg too long");+}else{+if(i2c_quirk_exceeded(len,max_write))+returni2c_quirk_error(adap,&msgs[i],"msg too long");+}
What about being more verbose in the error message, specifying if it
was a read or a write message that failed?
quoted hunk
+ }
+
+ return 0;
+}
+
/**
* __i2c_transfer - unlocked flavor of i2c_transfer
* @adap: Handle to I2C bus
@@ -2080,6 +2130,9 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) unsigned long orig_jiffies; int ret, try;+ if (adap->quirks && i2c_check_for_quirks(adap, msgs, num))+ return -EOPNOTSUPP;+ /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets * enabled. This is an efficient way of keeping the for-loop from * being executed when not needed.--