Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

counter: 104-quad-8: Add lock guards - generic interface

Add lock protection from race conditions to 104-quad-8 counter driver
generic interface code changes. Mutex calls used for protection.

Fixes: f1d8a071d45b ("counter: 104-quad-8: Add Generic Counter interface support")

Signed-off-by: Syed Nayyar Waris <syednwaris@gmail.com>
Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Syed Nayyar Waris and committed by
Jonathan Cameron
fc069262 76551a3c

+160 -34
+160 -34
drivers/counter/104-quad-8.c
··· 44 44 * @base: base port address of the IIO device 45 45 */ 46 46 struct quad8_iio { 47 + struct mutex lock; 47 48 struct counter_device counter; 48 49 unsigned int fck_prescaler[QUAD8_NUM_COUNTERS]; 49 50 unsigned int preset[QUAD8_NUM_COUNTERS]; ··· 124 123 /* Borrow XOR Carry effectively doubles count range */ 125 124 *val = (borrow ^ carry) << 24; 126 125 126 + mutex_lock(&priv->lock); 127 + 127 128 /* Reset Byte Pointer; transfer Counter to Output Latch */ 128 129 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, 129 130 base_offset + 1); 130 131 131 132 for (i = 0; i < 3; i++) 132 133 *val |= (unsigned int)inb(base_offset) << (8 * i); 134 + 135 + mutex_unlock(&priv->lock); 133 136 134 137 return IIO_VAL_INT; 135 138 case IIO_CHAN_INFO_ENABLE: ··· 165 160 if ((unsigned int)val > 0xFFFFFF) 166 161 return -EINVAL; 167 162 163 + mutex_lock(&priv->lock); 164 + 168 165 /* Reset Byte Pointer */ 169 166 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 170 167 ··· 190 183 /* Reset Error flag */ 191 184 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); 192 185 186 + mutex_unlock(&priv->lock); 187 + 193 188 return 0; 194 189 case IIO_CHAN_INFO_ENABLE: 195 190 /* only boolean values accepted */ 196 191 if (val < 0 || val > 1) 197 192 return -EINVAL; 193 + 194 + mutex_lock(&priv->lock); 198 195 199 196 priv->ab_enable[chan->channel] = val; 200 197 ··· 207 196 /* Load I/O control configuration */ 208 197 outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); 209 198 199 + mutex_unlock(&priv->lock); 200 + 210 201 return 0; 211 202 case IIO_CHAN_INFO_SCALE: 203 + mutex_lock(&priv->lock); 204 + 212 205 /* Quadrature scaling only available in quadrature mode */ 213 - if (!priv->quadrature_mode[chan->channel] && (val2 || val != 1)) 206 + if (!priv->quadrature_mode[chan->channel] && 207 + (val2 || val != 1)) { 208 + mutex_unlock(&priv->lock); 214 209 return -EINVAL; 210 + } 215 211 216 212 /* Only three gain states (1, 0.5, 0.25) */ 217 213 if (val == 1 && !val2) ··· 232 214 priv->quadrature_scale[chan->channel] = 2; 233 215 break; 234 216 default: 217 + mutex_unlock(&priv->lock); 235 218 return -EINVAL; 236 219 } 237 - else 220 + else { 221 + mutex_unlock(&priv->lock); 238 222 return -EINVAL; 223 + } 239 224 225 + mutex_unlock(&priv->lock); 240 226 return 0; 241 227 } 242 228 ··· 277 255 if (preset > 0xFFFFFF) 278 256 return -EINVAL; 279 257 258 + mutex_lock(&priv->lock); 259 + 280 260 priv->preset[chan->channel] = preset; 281 261 282 262 /* Reset Byte Pointer */ ··· 287 263 /* Set Preset Register */ 288 264 for (i = 0; i < 3; i++) 289 265 outb(preset >> (8 * i), base_offset); 266 + 267 + mutex_unlock(&priv->lock); 290 268 291 269 return len; 292 270 } ··· 319 293 /* Preset enable is active low in Input/Output Control register */ 320 294 preset_enable = !preset_enable; 321 295 296 + mutex_lock(&priv->lock); 297 + 322 298 priv->preset_enable[chan->channel] = preset_enable; 323 299 324 300 ior_cfg = priv->ab_enable[chan->channel] | ··· 328 300 329 301 /* Load I/O control configuration to Input / Output Control Register */ 330 302 outb(QUAD8_CTR_IOR | ior_cfg, base_offset); 303 + 304 + mutex_unlock(&priv->lock); 331 305 332 306 return len; 333 307 } ··· 388 358 unsigned int mode_cfg = cnt_mode << 1; 389 359 const int base_offset = priv->base + 2 * chan->channel + 1; 390 360 361 + mutex_lock(&priv->lock); 362 + 391 363 priv->count_mode[chan->channel] = cnt_mode; 392 364 393 365 /* Add quadrature mode configuration */ ··· 398 366 399 367 /* Load mode configuration to Counter Mode Register */ 400 368 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 369 + 370 + mutex_unlock(&priv->lock); 401 371 402 372 return 0; 403 373 } ··· 428 394 const struct iio_chan_spec *chan, unsigned int synchronous_mode) 429 395 { 430 396 struct quad8_iio *const priv = iio_priv(indio_dev); 431 - const unsigned int idr_cfg = synchronous_mode | 432 - priv->index_polarity[chan->channel] << 1; 433 397 const int base_offset = priv->base + 2 * chan->channel + 1; 398 + unsigned int idr_cfg = synchronous_mode; 399 + 400 + mutex_lock(&priv->lock); 401 + 402 + idr_cfg |= priv->index_polarity[chan->channel] << 1; 434 403 435 404 /* Index function must be non-synchronous in non-quadrature mode */ 436 - if (synchronous_mode && !priv->quadrature_mode[chan->channel]) 405 + if (synchronous_mode && !priv->quadrature_mode[chan->channel]) { 406 + mutex_unlock(&priv->lock); 437 407 return -EINVAL; 408 + } 438 409 439 410 priv->synchronous_mode[chan->channel] = synchronous_mode; 440 411 441 412 /* Load Index Control configuration to Index Control Register */ 442 413 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 414 + 415 + mutex_unlock(&priv->lock); 443 416 444 417 return 0; 445 418 } ··· 475 434 const struct iio_chan_spec *chan, unsigned int quadrature_mode) 476 435 { 477 436 struct quad8_iio *const priv = iio_priv(indio_dev); 478 - unsigned int mode_cfg = priv->count_mode[chan->channel] << 1; 479 437 const int base_offset = priv->base + 2 * chan->channel + 1; 438 + unsigned int mode_cfg; 439 + 440 + mutex_lock(&priv->lock); 441 + 442 + mode_cfg = priv->count_mode[chan->channel] << 1; 480 443 481 444 if (quadrature_mode) 482 445 mode_cfg |= (priv->quadrature_scale[chan->channel] + 1) << 3; ··· 497 452 498 453 /* Load mode configuration to Counter Mode Register */ 499 454 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 455 + 456 + mutex_unlock(&priv->lock); 500 457 501 458 return 0; 502 459 } ··· 527 480 const struct iio_chan_spec *chan, unsigned int index_polarity) 528 481 { 529 482 struct quad8_iio *const priv = iio_priv(indio_dev); 530 - const unsigned int idr_cfg = priv->synchronous_mode[chan->channel] | 531 - index_polarity << 1; 532 483 const int base_offset = priv->base + 2 * chan->channel + 1; 484 + unsigned int idr_cfg = index_polarity << 1; 485 + 486 + mutex_lock(&priv->lock); 487 + 488 + idr_cfg |= priv->synchronous_mode[chan->channel]; 533 489 534 490 priv->index_polarity[chan->channel] = index_polarity; 535 491 536 492 /* Load Index Control configuration to Index Control Register */ 537 493 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 494 + 495 + mutex_unlock(&priv->lock); 538 496 539 497 return 0; 540 498 } ··· 641 589 static int quad8_count_read(struct counter_device *counter, 642 590 struct counter_count *count, unsigned long *val) 643 591 { 644 - const struct quad8_iio *const priv = counter->priv; 592 + struct quad8_iio *const priv = counter->priv; 645 593 const int base_offset = priv->base + 2 * count->id; 646 594 unsigned int flags; 647 595 unsigned int borrow; ··· 655 603 /* Borrow XOR Carry effectively doubles count range */ 656 604 *val = (unsigned long)(borrow ^ carry) << 24; 657 605 606 + mutex_lock(&priv->lock); 607 + 658 608 /* Reset Byte Pointer; transfer Counter to Output Latch */ 659 609 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, 660 610 base_offset + 1); ··· 664 610 for (i = 0; i < 3; i++) 665 611 *val |= (unsigned long)inb(base_offset) << (8 * i); 666 612 613 + mutex_unlock(&priv->lock); 614 + 667 615 return 0; 668 616 } 669 617 670 618 static int quad8_count_write(struct counter_device *counter, 671 619 struct counter_count *count, unsigned long val) 672 620 { 673 - const struct quad8_iio *const priv = counter->priv; 621 + struct quad8_iio *const priv = counter->priv; 674 622 const int base_offset = priv->base + 2 * count->id; 675 623 int i; 676 624 677 625 /* Only 24-bit values are supported */ 678 626 if (val > 0xFFFFFF) 679 627 return -EINVAL; 628 + 629 + mutex_lock(&priv->lock); 680 630 681 631 /* Reset Byte Pointer */ 682 632 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); ··· 705 647 /* Reset Error flag */ 706 648 outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_E, base_offset + 1); 707 649 650 + mutex_unlock(&priv->lock); 651 + 708 652 return 0; 709 653 } 710 654 ··· 727 667 static int quad8_function_get(struct counter_device *counter, 728 668 struct counter_count *count, size_t *function) 729 669 { 730 - const struct quad8_iio *const priv = counter->priv; 670 + struct quad8_iio *const priv = counter->priv; 731 671 const int id = count->id; 732 - const unsigned int quadrature_mode = priv->quadrature_mode[id]; 733 - const unsigned int scale = priv->quadrature_scale[id]; 734 672 735 - if (quadrature_mode) 736 - switch (scale) { 673 + mutex_lock(&priv->lock); 674 + 675 + if (priv->quadrature_mode[id]) 676 + switch (priv->quadrature_scale[id]) { 737 677 case 0: 738 678 *function = QUAD8_COUNT_FUNCTION_QUADRATURE_X1; 739 679 break; ··· 747 687 else 748 688 *function = QUAD8_COUNT_FUNCTION_PULSE_DIRECTION; 749 689 690 + mutex_unlock(&priv->lock); 691 + 750 692 return 0; 751 693 } 752 694 ··· 759 697 const int id = count->id; 760 698 unsigned int *const quadrature_mode = priv->quadrature_mode + id; 761 699 unsigned int *const scale = priv->quadrature_scale + id; 762 - unsigned int mode_cfg = priv->count_mode[id] << 1; 763 700 unsigned int *const synchronous_mode = priv->synchronous_mode + id; 764 - const unsigned int idr_cfg = priv->index_polarity[id] << 1; 765 701 const int base_offset = priv->base + 2 * id + 1; 702 + unsigned int mode_cfg; 703 + unsigned int idr_cfg; 704 + 705 + mutex_lock(&priv->lock); 706 + 707 + mode_cfg = priv->count_mode[id] << 1; 708 + idr_cfg = priv->index_polarity[id] << 1; 766 709 767 710 if (function == QUAD8_COUNT_FUNCTION_PULSE_DIRECTION) { 768 711 *quadrature_mode = 0; ··· 802 735 803 736 /* Load mode configuration to Counter Mode Register */ 804 737 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 738 + 739 + mutex_unlock(&priv->lock); 805 740 806 741 return 0; 807 742 } ··· 921 852 { 922 853 struct quad8_iio *const priv = counter->priv; 923 854 const size_t channel_id = signal->id - 16; 924 - const unsigned int idr_cfg = priv->synchronous_mode[channel_id] | 925 - index_polarity << 1; 926 855 const int base_offset = priv->base + 2 * channel_id + 1; 856 + unsigned int idr_cfg = index_polarity << 1; 857 + 858 + mutex_lock(&priv->lock); 859 + 860 + idr_cfg |= priv->synchronous_mode[channel_id]; 927 861 928 862 priv->index_polarity[channel_id] = index_polarity; 929 863 930 864 /* Load Index Control configuration to Index Control Register */ 931 865 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 866 + 867 + mutex_unlock(&priv->lock); 932 868 933 869 return 0; 934 870 } ··· 961 887 { 962 888 struct quad8_iio *const priv = counter->priv; 963 889 const size_t channel_id = signal->id - 16; 964 - const unsigned int idr_cfg = synchronous_mode | 965 - priv->index_polarity[channel_id] << 1; 966 890 const int base_offset = priv->base + 2 * channel_id + 1; 891 + unsigned int idr_cfg = synchronous_mode; 892 + 893 + mutex_lock(&priv->lock); 894 + 895 + idr_cfg |= priv->index_polarity[channel_id] << 1; 967 896 968 897 /* Index function must be non-synchronous in non-quadrature mode */ 969 - if (synchronous_mode && !priv->quadrature_mode[channel_id]) 898 + if (synchronous_mode && !priv->quadrature_mode[channel_id]) { 899 + mutex_unlock(&priv->lock); 970 900 return -EINVAL; 901 + } 971 902 972 903 priv->synchronous_mode[channel_id] = synchronous_mode; 973 904 974 905 /* Load Index Control configuration to Index Control Register */ 975 906 outb(QUAD8_CTR_IDR | idr_cfg, base_offset); 907 + 908 + mutex_unlock(&priv->lock); 976 909 977 910 return 0; 978 911 } ··· 1045 964 break; 1046 965 } 1047 966 967 + mutex_lock(&priv->lock); 968 + 1048 969 priv->count_mode[count->id] = cnt_mode; 1049 970 1050 971 /* Set count mode configuration value */ ··· 1058 975 1059 976 /* Load mode configuration to Counter Mode Register */ 1060 977 outb(QUAD8_CTR_CMR | mode_cfg, base_offset); 978 + 979 + mutex_unlock(&priv->lock); 1061 980 1062 981 return 0; 1063 982 } ··· 1102 1017 if (err) 1103 1018 return err; 1104 1019 1020 + mutex_lock(&priv->lock); 1021 + 1105 1022 priv->ab_enable[count->id] = ab_enable; 1106 1023 1107 1024 ior_cfg = ab_enable | priv->preset_enable[count->id] << 1; 1108 1025 1109 1026 /* Load I/O control configuration */ 1110 1027 outb(QUAD8_CTR_IOR | ior_cfg, base_offset + 1); 1028 + 1029 + mutex_unlock(&priv->lock); 1111 1030 1112 1031 return len; 1113 1032 } ··· 1141 1052 return sprintf(buf, "%u\n", priv->preset[count->id]); 1142 1053 } 1143 1054 1055 + static void quad8_preset_register_set(struct quad8_iio *quad8iio, int id, 1056 + unsigned int preset) 1057 + { 1058 + const unsigned int base_offset = quad8iio->base + 2 * id; 1059 + int i; 1060 + 1061 + quad8iio->preset[id] = preset; 1062 + 1063 + /* Reset Byte Pointer */ 1064 + outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 1065 + 1066 + /* Set Preset Register */ 1067 + for (i = 0; i < 3; i++) 1068 + outb(preset >> (8 * i), base_offset); 1069 + } 1070 + 1144 1071 static ssize_t quad8_count_preset_write(struct counter_device *counter, 1145 1072 struct counter_count *count, void *private, const char *buf, size_t len) 1146 1073 { 1147 1074 struct quad8_iio *const priv = counter->priv; 1148 - const int base_offset = priv->base + 2 * count->id; 1149 1075 unsigned int preset; 1150 1076 int ret; 1151 - int i; 1152 1077 1153 1078 ret = kstrtouint(buf, 0, &preset); 1154 1079 if (ret) ··· 1172 1069 if (preset > 0xFFFFFF) 1173 1070 return -EINVAL; 1174 1071 1175 - priv->preset[count->id] = preset; 1072 + mutex_lock(&priv->lock); 1176 1073 1177 - /* Reset Byte Pointer */ 1178 - outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); 1074 + quad8_preset_register_set(priv, count->id, preset); 1179 1075 1180 - /* Set Preset Register */ 1181 - for (i = 0; i < 3; i++) 1182 - outb(preset >> (8 * i), base_offset); 1076 + mutex_unlock(&priv->lock); 1183 1077 1184 1078 return len; 1185 1079 } ··· 1184 1084 static ssize_t quad8_count_ceiling_read(struct counter_device *counter, 1185 1085 struct counter_count *count, void *private, char *buf) 1186 1086 { 1187 - const struct quad8_iio *const priv = counter->priv; 1087 + struct quad8_iio *const priv = counter->priv; 1088 + 1089 + mutex_lock(&priv->lock); 1188 1090 1189 1091 /* Range Limit and Modulo-N count modes use preset value as ceiling */ 1190 1092 switch (priv->count_mode[count->id]) { 1191 1093 case 1: 1192 1094 case 3: 1193 - return quad8_count_preset_read(counter, count, private, buf); 1095 + mutex_unlock(&priv->lock); 1096 + return sprintf(buf, "%u\n", priv->preset[count->id]); 1194 1097 } 1098 + 1099 + mutex_unlock(&priv->lock); 1195 1100 1196 1101 /* By default 0x1FFFFFF (25 bits unsigned) is maximum count */ 1197 1102 return sprintf(buf, "33554431\n"); ··· 1206 1101 struct counter_count *count, void *private, const char *buf, size_t len) 1207 1102 { 1208 1103 struct quad8_iio *const priv = counter->priv; 1104 + unsigned int ceiling; 1105 + int ret; 1106 + 1107 + ret = kstrtouint(buf, 0, &ceiling); 1108 + if (ret) 1109 + return ret; 1110 + 1111 + /* Only 24-bit values are supported */ 1112 + if (ceiling > 0xFFFFFF) 1113 + return -EINVAL; 1114 + 1115 + mutex_lock(&priv->lock); 1209 1116 1210 1117 /* Range Limit and Modulo-N count modes use preset value as ceiling */ 1211 1118 switch (priv->count_mode[count->id]) { 1212 1119 case 1: 1213 1120 case 3: 1214 - return quad8_count_preset_write(counter, count, private, buf, 1215 - len); 1121 + quad8_preset_register_set(priv, count->id, ceiling); 1122 + break; 1216 1123 } 1124 + 1125 + mutex_unlock(&priv->lock); 1217 1126 1218 1127 return len; 1219 1128 } ··· 1256 1137 /* Preset enable is active low in Input/Output Control register */ 1257 1138 preset_enable = !preset_enable; 1258 1139 1140 + mutex_lock(&priv->lock); 1141 + 1259 1142 priv->preset_enable[count->id] = preset_enable; 1260 1143 1261 1144 ior_cfg = priv->ab_enable[count->id] | (unsigned int)preset_enable << 1; 1262 1145 1263 1146 /* Load I/O control configuration to Input / Output Control Register */ 1264 1147 outb(QUAD8_CTR_IOR | ior_cfg, base_offset); 1148 + 1149 + mutex_unlock(&priv->lock); 1265 1150 1266 1151 return len; 1267 1152 } ··· 1551 1428 quad8iio->counter.num_signals = ARRAY_SIZE(quad8_signals); 1552 1429 quad8iio->counter.priv = quad8iio; 1553 1430 quad8iio->base = base[id]; 1431 + 1432 + /* Initialize mutex */ 1433 + mutex_init(&quad8iio->lock); 1554 1434 1555 1435 /* Reset all counters and disable interrupt function */ 1556 1436 outb(QUAD8_CHAN_OP_RESET_COUNTERS, base[id] + QUAD8_REG_CHAN_OP);