Commit 490916d6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'staging-3.7-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull staging driver fixes from Greg Kroah-Hartman:
 "Here are some staging driver fixes for your 3.7-rc tree.

  Nothing major here, a number of iio driver fixups that were causing
  problems, some comedi driver bugfixes, and a bunch of tidspbridge
  warning squashing and other regressions fixed from the 3.6 release.

  All have been in the linux-next releases for a bit.

  Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"

* tag 'staging-3.7-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (32 commits)
  staging: tidspbridge: delete unused mmu functions
  staging: tidspbridge: ioremap physical address of the stack segment in shm
  staging: tidspbridge: ioremap dsp sync addr
  staging: tidspbridge: change type to __iomem for per and core addresses
  staging: tidspbridge: drop const from custom mmu implementation
  staging: tidspbridge: request the right irq for mmu
  staging: ipack: add missing include (implicit declaration of function 'kfree')
  staging: ramster: depends on NET
  staging: omapdrm: fix allocation size for page addresses array
  staging: zram: Fix handling of incompressible pages
  Staging: android: binder: Allow using highmem for binder buffers
  Staging: android: binder: Fix memory leak on thread/process exit
  staging: comedi: ni_labpc: fix possible NULL deref during detach
  staging: comedi: das08: fix possible NULL deref during detach
  staging: comedi: amplc_pc263: fix possible NULL deref during detach
  staging: comedi: amplc_pc236: fix possible NULL deref during detach
  staging: comedi: amplc_pc236: fix invalid register access during detach
  staging: comedi: amplc_dio200: fix possible NULL deref during detach
  staging: comedi: 8255_pci: fix possible NULL deref during detach
  staging: comedi: ni_daq_700: fix dio subdevice regression
  ...
parents 299650ca 4d3f120a
...@@ -62,7 +62,6 @@ source "drivers/iio/frequency/Kconfig" ...@@ -62,7 +62,6 @@ source "drivers/iio/frequency/Kconfig"
source "drivers/iio/dac/Kconfig" source "drivers/iio/dac/Kconfig"
source "drivers/iio/common/Kconfig" source "drivers/iio/common/Kconfig"
source "drivers/iio/gyro/Kconfig" source "drivers/iio/gyro/Kconfig"
source "drivers/iio/light/Kconfig"
source "drivers/iio/magnetometer/Kconfig" source "drivers/iio/magnetometer/Kconfig"
endif # IIO endif # IIO
...@@ -18,5 +18,4 @@ obj-y += frequency/ ...@@ -18,5 +18,4 @@ obj-y += frequency/
obj-y += dac/ obj-y += dac/
obj-y += common/ obj-y += common/
obj-y += gyro/ obj-y += gyro/
obj-y += light/
obj-y += magnetometer/ obj-y += magnetometer/
...@@ -567,7 +567,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate, ...@@ -567,7 +567,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE];
BUG_ON(*page); BUG_ON(*page);
*page = alloc_page(GFP_KERNEL | __GFP_ZERO); *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
if (*page == NULL) { if (*page == NULL) {
pr_err("binder: %d: binder_alloc_buf failed " pr_err("binder: %d: binder_alloc_buf failed "
"for page at %p\n", proc->pid, page_addr); "for page at %p\n", proc->pid, page_addr);
...@@ -2419,14 +2419,38 @@ static void binder_release_work(struct list_head *list) ...@@ -2419,14 +2419,38 @@ static void binder_release_work(struct list_head *list)
struct binder_transaction *t; struct binder_transaction *t;
t = container_of(w, struct binder_transaction, work); t = container_of(w, struct binder_transaction, work);
if (t->buffer->target_node && !(t->flags & TF_ONE_WAY)) if (t->buffer->target_node &&
!(t->flags & TF_ONE_WAY)) {
binder_send_failed_reply(t, BR_DEAD_REPLY); binder_send_failed_reply(t, BR_DEAD_REPLY);
} else {
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"binder: undelivered transaction %d\n",
t->debug_id);
t->buffer->transaction = NULL;
kfree(t);
binder_stats_deleted(BINDER_STAT_TRANSACTION);
}
} break; } break;
case BINDER_WORK_TRANSACTION_COMPLETE: { case BINDER_WORK_TRANSACTION_COMPLETE: {
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"binder: undelivered TRANSACTION_COMPLETE\n");
kfree(w); kfree(w);
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
} break; } break;
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
struct binder_ref_death *death;
death = container_of(w, struct binder_ref_death, work);
binder_debug(BINDER_DEBUG_DEAD_TRANSACTION,
"binder: undelivered death notification, %p\n",
death->cookie);
kfree(death);
binder_stats_deleted(BINDER_STAT_DEATH);
} break;
default: default:
pr_err("binder: unexpected work type, %d, not freed\n",
w->type);
break; break;
} }
} }
...@@ -2899,6 +2923,7 @@ static void binder_deferred_release(struct binder_proc *proc) ...@@ -2899,6 +2923,7 @@ static void binder_deferred_release(struct binder_proc *proc)
nodes++; nodes++;
rb_erase(&node->rb_node, &proc->nodes); rb_erase(&node->rb_node, &proc->nodes);
list_del_init(&node->work.entry); list_del_init(&node->work.entry);
binder_release_work(&node->async_todo);
if (hlist_empty(&node->refs)) { if (hlist_empty(&node->refs)) {
kfree(node); kfree(node);
binder_stats_deleted(BINDER_STAT_NODE); binder_stats_deleted(BINDER_STAT_NODE);
...@@ -2937,6 +2962,7 @@ static void binder_deferred_release(struct binder_proc *proc) ...@@ -2937,6 +2962,7 @@ static void binder_deferred_release(struct binder_proc *proc)
binder_delete_ref(ref); binder_delete_ref(ref);
} }
binder_release_work(&proc->todo); binder_release_work(&proc->todo);
binder_release_work(&proc->delivered_death);
buffers = 0; buffers = 0;
while ((n = rb_first(&proc->allocated_buffers))) { while ((n = rb_first(&proc->allocated_buffers))) {
......
...@@ -289,6 +289,8 @@ static void pci_8255_detach(struct comedi_device *dev) ...@@ -289,6 +289,8 @@ static void pci_8255_detach(struct comedi_device *dev)
struct comedi_subdevice *s; struct comedi_subdevice *s;
int i; int i;
if (!board || !devpriv)
return;
if (dev->subdevices) { if (dev->subdevices) {
for (i = 0; i < board->n_8255; i++) { for (i = 0; i < board->n_8255; i++) {
s = &dev->subdevices[i]; s = &dev->subdevices[i];
......
...@@ -1410,6 +1410,8 @@ static void dio200_detach(struct comedi_device *dev) ...@@ -1410,6 +1410,8 @@ static void dio200_detach(struct comedi_device *dev)
const struct dio200_layout_struct *layout; const struct dio200_layout_struct *layout;
unsigned n; unsigned n;
if (!thisboard)
return;
if (dev->irq) if (dev->irq)
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
if (dev->subdevices) { if (dev->subdevices) {
......
...@@ -573,9 +573,10 @@ static int __devinit pc236_attach_pci(struct comedi_device *dev, ...@@ -573,9 +573,10 @@ static int __devinit pc236_attach_pci(struct comedi_device *dev,
static void pc236_detach(struct comedi_device *dev) static void pc236_detach(struct comedi_device *dev)
{ {
const struct pc236_board *thisboard = comedi_board(dev); const struct pc236_board *thisboard = comedi_board(dev);
struct pc236_private *devpriv = dev->private;
if (devpriv) if (!thisboard)
return;
if (dev->iobase)
pc236_intr_disable(dev); pc236_intr_disable(dev);
if (dev->irq) if (dev->irq)
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
......
...@@ -323,6 +323,8 @@ static void pc263_detach(struct comedi_device *dev) ...@@ -323,6 +323,8 @@ static void pc263_detach(struct comedi_device *dev)
{ {
const struct pc263_board *thisboard = comedi_board(dev); const struct pc263_board *thisboard = comedi_board(dev);
if (!thisboard)
return;
if (is_isa_board(thisboard)) { if (is_isa_board(thisboard)) {
if (dev->iobase) if (dev->iobase)
release_region(dev->iobase, PC263_IO_SIZE); release_region(dev->iobase, PC263_IO_SIZE);
......
...@@ -846,6 +846,8 @@ static void __maybe_unused das08_detach(struct comedi_device *dev) ...@@ -846,6 +846,8 @@ static void __maybe_unused das08_detach(struct comedi_device *dev)
{ {
const struct das08_board_struct *thisboard = comedi_board(dev); const struct das08_board_struct *thisboard = comedi_board(dev);
if (!thisboard)
return;
das08_common_detach(dev); das08_common_detach(dev);
if (is_isa_board(thisboard)) { if (is_isa_board(thisboard)) {
if (dev->iobase) if (dev->iobase)
......
...@@ -95,7 +95,7 @@ static int daq700_dio_insn_bits(struct comedi_device *dev, ...@@ -95,7 +95,7 @@ static int daq700_dio_insn_bits(struct comedi_device *dev,
} }
data[1] = s->state & 0xff; data[1] = s->state & 0xff;
data[1] |= inb(dev->iobase + DIO_R); data[1] |= inb(dev->iobase + DIO_R) << 8;
return insn->n; return insn->n;
} }
......
...@@ -772,6 +772,8 @@ void labpc_common_detach(struct comedi_device *dev) ...@@ -772,6 +772,8 @@ void labpc_common_detach(struct comedi_device *dev)
{ {
struct comedi_subdevice *s; struct comedi_subdevice *s;
if (!thisboard)
return;
if (dev->subdevices) { if (dev->subdevices) {
s = &dev->subdevices[2]; s = &dev->subdevices[2];
subdev_8255_cleanup(dev, s); subdev_8255_cleanup(dev, s);
......
...@@ -310,30 +310,32 @@ static int adis16201_read_raw(struct iio_dev *indio_dev, ...@@ -310,30 +310,32 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_VOLTAGE: case IIO_VOLTAGE:
*val = 0; if (chan->channel == 0) {
if (chan->channel == 0) *val = 1;
*val2 = 1220; *val2 = 220000; /* 1.22 mV */
else } else {
*val2 = 610; *val = 0;
*val2 = 610000; /* 0.610 mV */
}
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP: case IIO_TEMP:
*val = 0; *val = -470; /* 0.47 C */
*val2 = -470000; *val2 = 0;
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_ACCEL: case IIO_ACCEL:
*val = 0; *val = 0;
*val2 = 462500; *val2 = IIO_G_TO_M_S_2(462400); /* 0.4624 mg */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_NANO;
case IIO_INCLI: case IIO_INCLI:
*val = 0; *val = 0;
*val2 = 100000; *val2 = 100000; /* 0.1 degree */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
default: default:
return -EINVAL; return -EINVAL;
} }
break; break;
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
*val = 25; *val = 25000 / -470 - 1278; /* 25 C = 1278 */
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
switch (chan->type) { switch (chan->type) {
......
...@@ -316,25 +316,27 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, ...@@ -316,25 +316,27 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_VOLTAGE: case IIO_VOLTAGE:
*val = 0; if (chan->channel == 0) {
if (chan->channel == 0) *val = 1;
*val2 = 1220; *val2 = 220000; /* 1.22 mV */
else } else {
*val2 = 610; *val = 0;
*val2 = 610000; /* 0.61 mV */
}
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP: case IIO_TEMP:
*val = 0; *val = -470; /* -0.47 C */
*val2 = -470000; *val2 = 0;
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_INCLI: case IIO_INCLI:
*val = 0; *val = 0;
*val2 = 25000; *val2 = 25000; /* 0.025 degree */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
default: default:
return -EINVAL; return -EINVAL;
} }
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
*val = 25; *val = 25000 / -470 - 1278; /* 25 C = 1278 */
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
bits = 14; bits = 14;
......
...@@ -317,26 +317,28 @@ static int adis16204_read_raw(struct iio_dev *indio_dev, ...@@ -317,26 +317,28 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_VOLTAGE: case IIO_VOLTAGE:
*val = 0; if (chan->channel == 0) {
if (chan->channel == 0) *val = 1;
*val2 = 1220; *val2 = 220000; /* 1.22 mV */
else } else {
*val2 = 610; *val = 0;
*val2 = 610000; /* 0.61 mV */
}
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP: case IIO_TEMP:
*val = 0; *val = -470; /* 0.47 C */
*val2 = -470000; *val2 = 0;
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_ACCEL: case IIO_ACCEL:
*val = 0; *val = 0;
switch (chan->channel2) { switch (chan->channel2) {
case IIO_MOD_X: case IIO_MOD_X:
case IIO_MOD_ROOT_SUM_SQUARED_X_Y: case IIO_MOD_ROOT_SUM_SQUARED_X_Y:
*val2 = 17125; *val2 = IIO_G_TO_M_S_2(17125); /* 17.125 mg */
break; break;
case IIO_MOD_Y: case IIO_MOD_Y:
case IIO_MOD_Z: case IIO_MOD_Z:
*val2 = 8407; *val2 = IIO_G_TO_M_S_2(8407); /* 8.407 mg */
break; break;
} }
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
...@@ -345,7 +347,7 @@ static int adis16204_read_raw(struct iio_dev *indio_dev, ...@@ -345,7 +347,7 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
} }
break; break;
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
*val = 25; *val = 25000 / -470 - 1278; /* 25 C = 1278 */
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
case IIO_CHAN_INFO_PEAK: case IIO_CHAN_INFO_PEAK:
......
...@@ -343,28 +343,29 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, ...@@ -343,28 +343,29 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
case IIO_VOLTAGE: case IIO_VOLTAGE:
*val = 0; *val = 0;
if (chan->channel == 0) if (chan->channel == 0)
*val2 = 305180; *val2 = 305180; /* 0.30518 mV */
else else
*val2 = 610500; *val2 = 610500; /* 0.6105 mV */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP: case IIO_TEMP:
*val = 0; *val = -470; /* -0.47 C */
*val2 = -470000; *val2 = 0;
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_ACCEL: case IIO_ACCEL:
*val = 0; *val = 0;
*val2 = 2394; *val2 = IIO_G_TO_M_S_2(244140); /* 0.244140 mg */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_NANO;
case IIO_INCLI: case IIO_INCLI:
case IIO_ROT:
*val = 0; *val = 0;
*val2 = 436; *val2 = 25000; /* 0.025 degree */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
default: default:
return -EINVAL; return -EINVAL;
} }
break; break;
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
*val = 25; *val = 25000 / -470 - 0x4FE; /* 25 C = 0x4FE */
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
switch (chan->type) { switch (chan->type) {
...@@ -491,6 +492,7 @@ static const struct iio_chan_spec adis16209_channels[] = { ...@@ -491,6 +492,7 @@ static const struct iio_chan_spec adis16209_channels[] = {
.modified = 1, .modified = 1,
.channel2 = IIO_MOD_X, .channel2 = IIO_MOD_X,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = rot, .address = rot,
.scan_index = ADIS16209_SCAN_ROT, .scan_index = ADIS16209_SCAN_ROT,
.scan_type = { .scan_type = {
......
...@@ -486,7 +486,7 @@ static int adis16220_read_raw(struct iio_dev *indio_dev, ...@@ -486,7 +486,7 @@ static int adis16220_read_raw(struct iio_dev *indio_dev,
break; break;
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
if (chan->type == IIO_TEMP) { if (chan->type == IIO_TEMP) {
*val = 25; *val = 25000 / -470 - 1278; /* 25 C = 1278 */
return IIO_VAL_INT; return IIO_VAL_INT;
} }
addrind = 1; addrind = 1;
...@@ -495,19 +495,22 @@ static int adis16220_read_raw(struct iio_dev *indio_dev, ...@@ -495,19 +495,22 @@ static int adis16220_read_raw(struct iio_dev *indio_dev,
addrind = 2; addrind = 2;
break; break;
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
*val = 0;
switch (chan->type) { switch (chan->type) {
case IIO_TEMP: case IIO_TEMP:
*val2 = -470000; *val = -470; /* -0.47 C */
*val2 = 0;
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_ACCEL: case IIO_ACCEL:
*val2 = 1887042; *val2 = IIO_G_TO_M_S_2(19073); /* 19.073 g */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_VOLTAGE: case IIO_VOLTAGE:
if (chan->channel == 0) if (chan->channel == 0) {
*val2 = 0012221; *val = 1;
else /* Should really be dependent on VDD */ *val2 = 220700; /* 1.2207 mV */
*val2 = 305; } else {
/* Should really be dependent on VDD */
*val2 = 305180; /* 305.18 uV */
}
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
default: default:
return -EINVAL; return -EINVAL;
......
...@@ -373,30 +373,31 @@ static int adis16240_read_raw(struct iio_dev *indio_dev, ...@@ -373,30 +373,31 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE: case IIO_CHAN_INFO_SCALE:
switch (chan->type) { switch (chan->type) {
case IIO_VOLTAGE: case IIO_VOLTAGE:
*val = 0; if (chan->channel == 0) {
if (chan->channel == 0) *val = 4;
*val2 = 4880; *val2 = 880000; /* 4.88 mV */
else return IIO_VAL_INT_PLUS_MICRO;
} else {
return -EINVAL; return -EINVAL;
return IIO_VAL_INT_PLUS_MICRO; }
case IIO_TEMP: case IIO_TEMP:
*val = 0; *val = 244; /* 0.244 C */
*val2 = 244000; *val2 = 0;
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_ACCEL: case IIO_ACCEL:
*val = 0; *val = 0;
*val2 = 504062; *val2 = IIO_G_TO_M_S_2(51400); /* 51.4 mg */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
default: default:
return -EINVAL; return -EINVAL;
} }
break; break;
case IIO_CHAN_INFO_PEAK_SCALE: case IIO_CHAN_INFO_PEAK_SCALE:
*val = 6; *val = 0;
*val2 = 629295; *val2 = IIO_G_TO_M_S_2(51400); /* 51.4 mg */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
*val = 25; *val = 25000 / 244 - 0x133; /* 25 C = 0x133 */
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
bits = 10; bits = 10;
......
...@@ -498,28 +498,33 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, ...@@ -498,28 +498,33 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
switch (chan->type) { switch (chan->type) {
case IIO_ANGL_VEL: case IIO_ANGL_VEL:
*val = 0; *val = 0;
if (spi_get_device_id(st->us)->driver_data) if (spi_get_device_id(st->us)->driver_data) {
*val2 = 320; /* 0.01832 degree / sec */
else *val2 = IIO_DEGREE_TO_RAD(18320);
*val2 = 1278; } else {
/* 0.07326 degree / sec */
*val2 = IIO_DEGREE_TO_RAD(73260);
}
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_VOLTAGE: case IIO_VOLTAGE:
*val = 0; if (chan->channel == 0) {
if (chan->channel == 0) *val = 1;
*val2 = 18315; *val2 = 831500; /* 1.8315 mV */
else } else {
*val2 = 610500; *val = 0;
*val2 = 610500; /* 610.5 uV */
}
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP: case IIO_TEMP:
*val = 0; *val = 145;
*val2 = 145300; *val2 = 300000; /* 0.1453 C */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
default: default:
return -EINVAL; return -EINVAL;
} }
break; break;
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
*val = 25; *val = 250000 / 1453; /* 25 C = 0x00 */
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBBIAS: case IIO_CHAN_INFO_CALIBBIAS:
switch (chan->type) { switch (chan->type) {
......
...@@ -139,6 +139,8 @@ struct adis16400_chip_info { ...@@ -139,6 +139,8 @@ struct adis16400_chip_info {
const long flags; const long flags;
unsigned int gyro_scale_micro; unsigned int gyro_scale_micro;
unsigned int accel_scale_micro; unsigned int accel_scale_micro;
int temp_scale_nano;
int temp_offset;
unsigned long default_scan_mask; unsigned long default_scan_mask;
}; };
......
...@@ -553,10 +553,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -553,10 +553,13 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_VOLTAGE: case IIO_VOLTAGE:
*val = 0; *val = 0;
if (chan->channel == 0) if (chan->channel == 0) {
*val2 = 2418; *val = 2;
else *val2 = 418000; /* 2.418 mV */
*val2 = 806; } else {
*val = 0;
*val2 = 805800; /* 805.8 uV */
}
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_ACCEL: case IIO_ACCEL:
*val = 0; *val = 0;
...@@ -564,11 +567,11 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -564,11 +567,11 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_MAGN: case IIO_MAGN:
*val = 0; *val = 0;
*val2 = 500; *val2 = 500; /* 0.5 mgauss */
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_TEMP: case IIO_TEMP:
*val = 0; *val = st->variant->temp_scale_nano / 1000000;
*val2 = 140000; *val2 = (st->variant->temp_scale_nano % 1000000);
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
default: default:
return -EINVAL; return -EINVAL;
...@@ -586,9 +589,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ...@@ -586,9 +589,8 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT; return IIO_VAL_INT;
case IIO_CHAN_INFO_OFFSET: case IIO_CHAN_INFO_OFFSET:
/* currently only temperature */ /* currently only temperature */
*val = 198; *val = st->variant->temp_offset;
*val2 = 160000; return IIO_VAL_INT;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
mutex_lock(&indio_dev->mlock); mutex_lock(&indio_dev->mlock);
/* Need both the number of taps and the sampling frequency */ /* Need both the number of taps and the sampling frequency */
...@@ -1035,7 +1037,7 @@ static const struct iio_chan_spec adis16334_channels[] = { ...@@ -1035,7 +1037,7 @@ static const struct iio_chan_spec adis16334_channels[] = {
.indexed = 1, .indexed = 1,
.channel = 0, .channel = 0,
.info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT, IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = temp0, .address = temp0,
.scan_index = ADIS16400_SCAN_TEMP, .scan_index = ADIS16400_SCAN_TEMP,
...@@ -1058,8 +1060,10 @@ static struct adis16400_chip_info adis16400_chips[] = { ...@@ -1058,8 +1060,10 @@ static struct adis16400_chip_info adis16400_chips[] = {
[ADIS16300] = { [ADIS16300] = {
.channels = adis16300_channels, .channels = adis16300_channels,
.num_channels = ARRAY_SIZE(adis16300_channels), .num_channels = ARRAY_SIZE(adis16300_channels),
.gyro_scale_micro = 873, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
.accel_scale_micro = 5884, .accel_scale_micro = 5884,
.temp_scale_nano = 140000000, /* 0.14 C */
.temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
.default_scan_mask = (1 << ADIS16400_SCAN_SUPPLY) | .default_scan_mask = (1 << ADIS16400_SCAN_SUPPLY) |
(1 << ADIS16400_SCAN_GYRO_X) | (1 << ADIS16400_SCAN_ACC_X) | (1 << ADIS16400_SCAN_GYRO_X) | (1 << ADIS16400_SCAN_ACC_X) |
(1 << ADIS16400_SCAN_ACC_Y) | (1 << ADIS16400_SCAN_ACC_Z) | (1 << ADIS16400_SCAN_ACC_Y) | (1 << ADIS16400_SCAN_ACC_Z) |
...@@ -1070,8 +1074,10 @@ static struct adis16400_chip_info adis16400_chips[] = { ...@@ -1070,8 +1074,10 @@ static struct adis16400_chip_info adis16400_chips[] = {
[ADIS16334] = { [ADIS16334] = {
.channels = adis16334_channels, .channels = adis16334_channels,
.num_channels = ARRAY_SIZE(adis16334_channels), .num_channels = ARRAY_SIZE(adis16334_channels),
.gyro_scale_micro = 873, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
.accel_scale_micro = 981, .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
.temp_scale_nano = 67850000, /* 0.06785 C */
.temp_offset = 25000000 / 67850, /* 25 C = 0x00 */
.default_scan_mask = (1 << ADIS16400_SCAN_GYRO_X) | .default_scan_mask = (1 << ADIS16400_SCAN_GYRO_X) |
(1 << ADIS16400_SCAN_GYRO_Y) | (1 << ADIS16400_SCAN_GYRO_Z) | (1 << ADIS16400_SCAN_GYRO_Y) | (1 << ADIS16400_SCAN_GYRO_Z) |
(1 << ADIS16400_SCAN_ACC_X) | (1 << ADIS16400_SCAN_ACC_Y) | (1 << ADIS16400_SCAN_ACC_X) | (1 << ADIS16400_SCAN_ACC_Y) |
...@@ -1080,8 +1086,10 @@ static struct adis16400_chip_info adis16400_chips[] = { ...@@ -1080,8 +1086,10 @@ static struct adis16400_chip_info adis16400_chips[] = {
[ADIS16350] = { [ADIS16350] = {
.channels = adis16350_channels, .channels = adis16350_channels,
.num_channels = ARRAY_SIZE(adis16350_channels), .num_channels = ARRAY_SIZE(adis16350_channels),
.gyro_scale_micro = 872664, .gyro_scale_micro = IIO_DEGREE_TO_RAD(73260), /* 0.07326 deg/s */
.accel_scale_micro = 24732, .accel_scale_micro = IIO_G_TO_M_S_2(2522), /* 0.002522 g */
.temp_scale_nano = 145300000, /* 0.1453 C */
.temp_offset = 25000000 / 145300, /* 25 C = 0x00 */
.default_scan_mask = 0x7FF, .default_scan_mask = 0x7FF,
.flags = ADIS16400_NO_BURST, .flags = ADIS16400_NO_BURST,
}, },
...@@ -1090,8 +1098,10 @@ static struct adis16400_chip_info adis16400_chips[] = { ...@@ -1090,8 +1098,10 @@ static struct adis16400_chip_info adis16400_chips[] = {
.num_channels = ARRAY_SIZE(adis16350_channels), .num_channels = ARRAY_SIZE(adis16350_channels),
.flags = ADIS16400_HAS_PROD_ID, .flags = ADIS16400_HAS_PROD_ID,
.product_id = 0x3FE8, .product_id = 0x3FE8,
.gyro_scale_micro = 1279, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
.accel_scale_micro = 24732, .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
.temp_scale_nano = 136000000, /* 0.136 C */
.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
.default_scan_mask = 0x7FF, .default_scan_mask = 0x7FF,
}, },
[ADIS16362] = { [ADIS16362] = {
...@@ -1099,8 +1109,10 @@ static struct adis16400_chip_info adis16400_chips[] = { ...@@ -1099,8 +1109,10 @@ static struct adis16400_chip_info adis16400_chips[] = {
.num_channels = ARRAY_SIZE(adis16350_channels), .num_channels = ARRAY_SIZE(adis16350_channels),
.flags = ADIS16400_HAS_PROD_ID, .flags = ADIS16400_HAS_PROD_ID,
.product_id = 0x3FEA, .product_id = 0x3FEA,
.gyro_scale_micro = 1279, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
.accel_scale_micro = 24732, .accel_scale_micro = IIO_G_TO_M_S_2(333), /* 0.333 mg */
.temp_scale_nano = 136000000, /* 0.136 C */
.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
.default_scan_mask = 0x7FF, .default_scan_mask = 0x7FF,
}, },
[ADIS16364] = { [ADIS16364] = {
...@@ -1108,8 +1120,10 @@ static struct adis16400_chip_info adis16400_chips[] = { ...@@ -1108,8 +1120,10 @@ static struct adis16400_chip_info adis16400_chips[] = {
.num_channels = ARRAY_SIZE(adis16350_channels), .num_channels = ARRAY_SIZE(adis16350_channels),
.flags = ADIS16400_HAS_PROD_ID, .flags = ADIS16400_HAS_PROD_ID,
.product_id = 0x3FEC, .product_id = 0x3FEC,
.gyro_scale_micro = 1279, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
.accel_scale_micro = 24732, .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
.temp_scale_nano = 136000000, /* 0.136 C */
.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
.default_scan_mask = 0x7FF, .default_scan_mask = 0x7FF,
}, },
[ADIS16365] = { [ADIS16365] = {
...@@ -1117,8 +1131,10 @@ static struct adis16400_chip_info adis16400_chips[] = { ...@@ -1117,8 +1131,10 @@ static struct adis16400_chip_info adis16400_chips[] = {
.num_channels = ARRAY_SIZE(adis16350_channels), .num_channels = ARRAY_SIZE(adis16350_channels),
.flags = ADIS16400_HAS_PROD_ID, .flags = ADIS16400_HAS_PROD_ID,
.product_id = 0x3FED, .product_id = 0x3FED,
.gyro_scale_micro = 1279, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
.accel_scale_micro = 24732, .accel_scale_micro = IIO_G_TO_M_S_2(1000), /* 1 mg */
.temp_scale_nano = 136000000, /* 0.136 C */
.temp_offset = 25000000 / 136000, /* 25 C = 0x00 */
.default_scan_mask = 0x7FF, .default_scan_mask = 0x7FF,
}, },
[ADIS16400] = { [ADIS16400] = {
...@@ -1126,9 +1142,11 @@ static struct adis16400_chip_info adis16400_chips[] = { ...@@ -1126,9 +1142,11 @@ static struct adis16400_chip_info adis16400_chips[] = {
.num_channels = ARRAY_SIZE(adis16400_channels), .num_channels = ARRAY_SIZE(adis16400_channels),
.flags = ADIS16400_HAS_PROD_ID, .flags = ADIS16400_HAS_PROD_ID,
.product_id = 0x4015, .product_id = 0x4015,
.gyro_scale_micro = 873, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */
.accel_scale_micro = 32656, .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */
.default_scan_mask = 0xFFF, .default_scan_mask = 0xFFF,
.temp_scale_nano = 140000000, /* 0.14 C */
.temp_offset = 25000000 / 140000, /* 25 C = 0x00 */
} }
}; };
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h>
#include "tpci200.h" #include "tpci200.h"
static u16 tpci200_status_timeout[] = { static u16 tpci200_status_timeout[] = {
......
...@@ -246,7 +246,7 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) ...@@ -246,7 +246,7 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj)
* DSS, GPU, etc. are not cache coherent: * DSS, GPU, etc. are not cache coherent:
*/ */
if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) { if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) {
addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL); addrs = kmalloc(npages * sizeof(*addrs), GFP_KERNEL);
if (!addrs) { if (!addrs) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_pages; goto free_pages;
...@@ -257,7 +257,7 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) ...@@ -257,7 +257,7 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj)
0, PAGE_SIZE, DMA_BIDIRECTIONAL); 0, PAGE_SIZE, DMA_BIDIRECTIONAL);
} }
} else { } else {
addrs = kzalloc(npages * sizeof(addrs), GFP_KERNEL); addrs = kzalloc(npages * sizeof(*addrs), GFP_KERNEL);
if (!addrs) { if (!addrs) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_pages; goto free_pages;
......
...@@ -18,6 +18,7 @@ config ZCACHE2 ...@@ -18,6 +18,7 @@ config ZCACHE2
config RAMSTER config RAMSTER
bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem" bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem"
depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE2=y depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE2=y
depends on NET
# must ensure struct page is 8-byte aligned # must ensure struct page is 8-byte aligned
select HAVE_ALIGNED_STRUCT_PAGE if !64_BIT select HAVE_ALIGNED_STRUCT_PAGE if !64_BIT
default n default n
......
...@@ -126,7 +126,8 @@ static int mem_map_vmalloc(struct bridge_dev_context *dev_context, ...@@ -126,7 +126,8 @@ static int mem_map_vmalloc(struct bridge_dev_context *dev_context,
u32 ul_num_bytes, u32 ul_num_bytes,
struct hw_mmu_map_attrs_t *hw_attrs); struct hw_mmu_map_attrs_t *hw_attrs);
bool wait_for_start(struct bridge_dev_context *dev_context, u32 dw_sync_addr); bool wait_for_start(struct bridge_dev_context *dev_context,
void __iomem *sync_addr);
/* ----------------------------------- Globals */ /* ----------------------------------- Globals */
...@@ -363,10 +364,11 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, ...@@ -363,10 +364,11 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
{ {
int status = 0; int status = 0;
struct bridge_dev_context *dev_context = dev_ctxt; struct bridge_dev_context *dev_context = dev_ctxt;
u32 dw_sync_addr = 0; void __iomem *sync_addr;
u32 ul_shm_base; /* Gpp Phys SM base addr(byte) */ u32 ul_shm_base; /* Gpp Phys SM base addr(byte) */
u32 ul_shm_base_virt; /* Dsp Virt SM base addr */ u32 ul_shm_base_virt; /* Dsp Virt SM base addr */
u32 ul_tlb_base_virt; /* Base of MMU TLB entry */ u32 ul_tlb_base_virt; /* Base of MMU TLB entry */
u32 shm_sync_pa;
/* Offset of shm_base_virt from tlb_base_virt */ /* Offset of shm_base_virt from tlb_base_virt */
u32 ul_shm_offset_virt; u32 ul_shm_offset_virt;
s32 entry_ndx; s32 entry_ndx;
...@@ -397,15 +399,22 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, ...@@ -397,15 +399,22 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
/* Kernel logical address */ /* Kernel logical address */
ul_shm_base = dev_context->atlb_entry[0].gpp_va + ul_shm_offset_virt; ul_shm_base = dev_context->atlb_entry[0].gpp_va + ul_shm_offset_virt;
/* SHM physical sync address */
shm_sync_pa = dev_context->atlb_entry[0].gpp_pa + ul_shm_offset_virt +
SHMSYNCOFFSET;
/* 2nd wd is used as sync field */ /* 2nd wd is used as sync field */
dw_sync_addr = ul_shm_base + SHMSYNCOFFSET; sync_addr = ioremap(shm_sync_pa, SZ_32);
if (!sync_addr)
return -ENOMEM;
/* Write a signature into the shm base + offset; this will /* Write a signature into the shm base + offset; this will
* get cleared when the DSP program starts. */ * get cleared when the DSP program starts. */
if ((ul_shm_base_virt == 0) || (ul_shm_base == 0)) { if ((ul_shm_base_virt == 0) || (ul_shm_base == 0)) {
pr_err("%s: Illegal SM base\n", __func__); pr_err("%s: Illegal SM base\n", __func__);
status = -EPERM; status = -EPERM;
} else } else
__raw_writel(0xffffffff, dw_sync_addr); __raw_writel(0xffffffff, sync_addr);
if (!status) { if (!status) {
resources = dev_context->resources; resources = dev_context->resources;
...@@ -419,8 +428,10 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, ...@@ -419,8 +428,10 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
* function is made available. * function is made available.
*/ */
void __iomem *ctrl = ioremap(0x48002000, SZ_4K); void __iomem *ctrl = ioremap(0x48002000, SZ_4K);
if (!ctrl) if (!ctrl) {
iounmap(sync_addr);
return -ENOMEM; return -ENOMEM;
}
(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK, (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK,
OMAP3430_RST1_IVA2_MASK, OMAP3430_IVA2_MOD, OMAP3430_RST1_IVA2_MASK, OMAP3430_IVA2_MOD,
...@@ -588,15 +599,15 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, ...@@ -588,15 +599,15 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
(*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK, 0, (*pdata->dsp_prm_rmw_bits)(OMAP3430_RST1_IVA2_MASK, 0,
OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
dev_dbg(bridge, "Waiting for Sync @ 0x%x\n", dw_sync_addr); dev_dbg(bridge, "Waiting for Sync @ 0x%x\n", *(u32 *)sync_addr);
dev_dbg(bridge, "DSP c_int00 Address = 0x%x\n", dsp_addr); dev_dbg(bridge, "DSP c_int00 Address = 0x%x\n", dsp_addr);
if (dsp_debug) if (dsp_debug)
while (__raw_readw(dw_sync_addr)) while (__raw_readw(sync_addr))
; ;
/* Wait for DSP to clear word in shared memory */ /* Wait for DSP to clear word in shared memory */
/* Read the Location */ /* Read the Location */
if (!wait_for_start(dev_context, dw_sync_addr)) if (!wait_for_start(dev_context, sync_addr))
status = -ETIMEDOUT; status = -ETIMEDOUT;
dev_get_symbol(dev_context->dev_obj, "_WDT_enable", &wdt_en); dev_get_symbol(dev_context->dev_obj, "_WDT_enable", &wdt_en);
...@@ -612,7 +623,7 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, ...@@ -612,7 +623,7 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
/* Write the synchronization bit to indicate the /* Write the synchronization bit to indicate the
* completion of OPP table update to DSP * completion of OPP table update to DSP
*/ */
__raw_writel(0XCAFECAFE, dw_sync_addr); __raw_writel(0XCAFECAFE, sync_addr);
/* update board state */ /* update board state */
dev_context->brd_state = BRD_RUNNING; dev_context->brd_state = BRD_RUNNING;
...@@ -621,6 +632,9 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, ...@@ -621,6 +632,9 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
dev_context->brd_state = BRD_UNKNOWN; dev_context->brd_state = BRD_UNKNOWN;
} }
} }
iounmap(sync_addr);
return status; return status;
} }
...@@ -1796,12 +1810,13 @@ static int mem_map_vmalloc(struct bridge_dev_context *dev_context, ...@@ -1796,12 +1810,13 @@ static int mem_map_vmalloc(struct bridge_dev_context *dev_context,
* ======== wait_for_start ======== * ======== wait_for_start ========
* Wait for the singal from DSP that it has started, or time out. * Wait for the singal from DSP that it has started, or time out.
*/ */
bool wait_for_start(struct bridge_dev_context *dev_context, u32 dw_sync_addr) bool wait_for_start(struct bridge_dev_context *dev_context,
void __iomem *sync_addr)
{ {
u16 timeout = TIHELEN_ACKTIMEOUT; u16 timeout = TIHELEN_ACKTIMEOUT;
/* Wait for response from board */ /* Wait for response from board */
while (__raw_readw(dw_sync_addr) && --timeout) while (__raw_readw(sync_addr) && --timeout)
udelay(10); udelay(10);
/* If timed out: return false */ /* If timed out: return false */
......
...@@ -47,38 +47,13 @@ enum hw_mmu_page_size_t { ...@@ -47,38 +47,13 @@ enum hw_mmu_page_size_t {
HW_MMU_SUPERSECTION HW_MMU_SUPERSECTION
}; };
/*
* FUNCTION : mmu_flush_entry
*
* INPUTS:
*
* Identifier : base_address
* Type : const u32
* Description : Base Address of instance of MMU module
*
* RETURNS:
*
* Type : hw_status
* Description : 0 -- No errors occurred
* RET_BAD_NULL_PARAM -- A Pointer
* Parameter was set to NULL
*
* PURPOSE: : Flush the TLB entry pointed by the
* lock counter register
* even if this entry is set protected
*
* METHOD: : Check the Input parameter and Flush a
* single entry in the TLB.
*/
static hw_status mmu_flush_entry(const void __iomem *base_address);
/* /*
* FUNCTION : mmu_set_cam_entry * FUNCTION : mmu_set_cam_entry
* *
* INPUTS: * INPUTS:
* *
* Identifier : base_address * Identifier : base_address
* TypE : const u32 * Type : void __iomem *
* Description : Base Address of instance of MMU module * Description : Base Address of instance of MMU module
* *
* Identifier : page_sz * Identifier : page_sz
...@@ -112,7 +87,7 @@ static hw_status mmu_flush_entry(const void __iomem *base_address); ...@@ -112,7 +87,7 @@ static hw_status mmu_flush_entry(const void __iomem *base_address);
* *
* METHOD: : Check the Input parameters and set the CAM entry. * METHOD: : Check the Input parameters and set the CAM entry.
*/ */
static hw_status mmu_set_cam_entry(const void __iomem *base_address, static hw_status mmu_set_cam_entry(void __iomem *base_address,
const u32 page_sz, const u32 page_sz,
const u32 preserved_bit, const u32 preserved_bit,
const u32 valid_bit, const u32 valid_bit,
...@@ -124,7 +99,7 @@ static hw_status mmu_set_cam_entry(const void __iomem *base_address, ...@@ -124,7 +99,7 @@ static hw_status mmu_set_cam_entry(const void __iomem *base_address,
* INPUTS: * INPUTS:
* *
* Identifier : base_address * Identifier : base_address
* Type : const u32 * Type : void __iomem *
* Description : Base Address of instance of MMU module * Description : Base Address of instance of MMU module
* *
* Identifier : physical_addr * Identifier : physical_addr
...@@ -157,7 +132,7 @@ static hw_status mmu_set_cam_entry(const void __iomem *base_address, ...@@ -157,7 +132,7 @@ static hw_status mmu_set_cam_entry(const void __iomem *base_address,
* *
* METHOD: : Check the Input parameters and set the RAM entry. * METHOD: : Check the Input parameters and set the RAM entry.
*/ */
static hw_status mmu_set_ram_entry(const void __iomem *base_address, static hw_status mmu_set_ram_entry(void __iomem *base_address,
const u32 physical_addr, const u32 physical_addr,
enum hw_endianism_t endianism, enum hw_endianism_t endianism,
enum hw_element_size_t element_size, enum hw_element_size_t element_size,
...@@ -165,7 +140,7 @@ static hw_status mmu_set_ram_entry(const void __iomem *base_address, ...@@ -165,7 +140,7 @@ static hw_status mmu_set_ram_entry(const void __iomem *base_address,
/* HW FUNCTIONS */ /* HW FUNCTIONS */
hw_status hw_mmu_enable(const void __iomem *base_address) hw_status hw_mmu_enable(void __iomem *base_address)
{ {
hw_status status = 0; hw_status status = 0;
...@@ -174,7 +149,7 @@ hw_status hw_mmu_enable(const void __iomem *base_address) ...@@ -174,7 +149,7 @@ hw_status hw_mmu_enable(const void __iomem *base_address)
return status; return status;
} }
hw_status hw_mmu_disable(const void __iomem *base_address) hw_status hw_mmu_disable(void __iomem *base_address)
{ {
hw_status status = 0; hw_status status = 0;
...@@ -183,7 +158,7 @@ hw_status hw_mmu_disable(const void __iomem *base_address) ...@@ -183,7 +158,7 @@ hw_status hw_mmu_disable(const void __iomem *base_address)
return status; return status;
} }
hw_status hw_mmu_num_locked_set(const void __iomem *base_address, hw_status hw_mmu_num_locked_set(void __iomem *base_address,
u32 num_locked_entries) u32 num_locked_entries)
{ {
hw_status status = 0; hw_status status = 0;
...@@ -193,7 +168,7 @@ hw_status hw_mmu_num_locked_set(const void __iomem *base_address, ...@@ -193,7 +168,7 @@ hw_status hw_mmu_num_locked_set(const void __iomem *base_address,
return status; return status;
} }
hw_status hw_mmu_victim_num_set(const void __iomem *base_address, hw_status hw_mmu_victim_num_set(void __iomem *base_address,
u32 victim_entry_num) u32 victim_entry_num)
{ {
hw_status status = 0; hw_status status = 0;
...@@ -203,7 +178,7 @@ hw_status hw_mmu_victim_num_set(const void __iomem *base_address, ...@@ -203,7 +178,7 @@ hw_status hw_mmu_victim_num_set(const void __iomem *base_address,
return status; return status;
} }
hw_status hw_mmu_event_ack(const void __iomem *base_address, u32 irq_mask) hw_status hw_mmu_event_ack(void __iomem *base_address, u32 irq_mask)
{ {
hw_status status = 0; hw_status status = 0;
...@@ -212,7 +187,7 @@ hw_status hw_mmu_event_ack(const void __iomem *base_address, u32 irq_mask) ...@@ -212,7 +187,7 @@ hw_status hw_mmu_event_ack(const void __iomem *base_address, u32 irq_mask)
return status; return status;
} }
hw_status hw_mmu_event_disable(const void __iomem *base_address, u32 irq_mask) hw_status hw_mmu_event_disable(void __iomem *base_address, u32 irq_mask)
{ {
hw_status status = 0; hw_status status = 0;
u32 irq_reg; u32 irq_reg;
...@@ -224,7 +199,7 @@ hw_status hw_mmu_event_disable(const void __iomem *base_address, u32 irq_mask) ...@@ -224,7 +199,7 @@ hw_status hw_mmu_event_disable(const void __iomem *base_address, u32 irq_mask)
return status; return status;
} }
hw_status hw_mmu_event_enable(const void __iomem *base_address, u32 irq_mask) hw_status hw_mmu_event_enable(void __iomem *base_address, u32 irq_mask)
{ {
hw_status status = 0; hw_status status = 0;
u32 irq_reg; u32 irq_reg;
...@@ -236,7 +211,7 @@ hw_status hw_mmu_event_enable(const void __iomem *base_address, u32 irq_mask) ...@@ -236,7 +211,7 @@ hw_status hw_mmu_event_enable(const void __iomem *base_address, u32 irq_mask)
return status; return status;
} }
hw_status hw_mmu_event_status(const void __iomem *base_address, u32 *irq_mask) hw_status hw_mmu_event_status(void __iomem *base_address, u32 *irq_mask)
{ {
hw_status status = 0; hw_status status = 0;
...@@ -245,7 +220,7 @@ hw_status hw_mmu_event_status(const void __iomem *base_address, u32 *irq_mask) ...@@ -245,7 +220,7 @@ hw_status hw_mmu_event_status(const void __iomem *base_address, u32 *irq_mask)
return status; return status;
} }
hw_status hw_mmu_fault_addr_read(const void __iomem *base_address, u32 *addr) hw_status hw_mmu_fault_addr_read(void __iomem *base_address, u32 *addr)
{ {
hw_status status = 0; hw_status status = 0;
...@@ -255,7 +230,7 @@ hw_status hw_mmu_fault_addr_read(const void __iomem *base_address, u32 *addr) ...@@ -255,7 +230,7 @@ hw_status hw_mmu_fault_addr_read(const void __iomem *base_address, u32 *addr)
return status; return status;
} }
hw_status hw_mmu_ttb_set(const void __iomem *base_address, u32 ttb_phys_addr) hw_status hw_mmu_ttb_set(void __iomem *base_address, u32 ttb_phys_addr)
{ {
hw_status status = 0; hw_status status = 0;
u32 load_ttb; u32 load_ttb;
...@@ -267,7 +242,7 @@ hw_status hw_mmu_ttb_set(const void __iomem *base_address, u32 ttb_phys_addr) ...@@ -267,7 +242,7 @@ hw_status hw_mmu_ttb_set(const void __iomem *base_address, u32 ttb_phys_addr)
return status; return status;
} }
hw_status hw_mmu_twl_enable(const void __iomem *base_address) hw_status hw_mmu_twl_enable(void __iomem *base_address)
{ {
hw_status status = 0; hw_status status = 0;
...@@ -276,7 +251,7 @@ hw_status hw_mmu_twl_enable(const void __iomem *base_address) ...@@ -276,7 +251,7 @@ hw_status hw_mmu_twl_enable(const void __iomem *base_address)
return status; return status;
} }
hw_status hw_mmu_twl_disable(const void __iomem *base_address) hw_status hw_mmu_twl_disable(void __iomem *base_address)
{ {
hw_status status = 0; hw_status status = 0;
...@@ -285,45 +260,7 @@ hw_status hw_mmu_twl_disable(const void __iomem *base_address) ...@@ -285,45 +260,7 @@ hw_status hw_mmu_twl_disable(const void __iomem *base_address)
return status; return status;
} }
hw_status hw_mmu_tlb_flush(const void __iomem *base_address, u32 virtual_addr, hw_status hw_mmu_tlb_add(void __iomem *base_address,
u32 page_sz)
{
hw_status status = 0;
u32 virtual_addr_tag;
enum hw_mmu_page_size_t pg_size_bits;
switch (page_sz) {
case HW_PAGE_SIZE4KB:
pg_size_bits = HW_MMU_SMALL_PAGE;
break;
case HW_PAGE_SIZE64KB:
pg_size_bits = HW_MMU_LARGE_PAGE;
break;
case HW_PAGE_SIZE1MB:
pg_size_bits = HW_MMU_SECTION;
break;
case HW_PAGE_SIZE16MB:
pg_size_bits = HW_MMU_SUPERSECTION;
break;
default:
return -EINVAL;
}
/* Generate the 20-bit tag from virtual address */
virtual_addr_tag = ((virtual_addr & MMU_ADDR_MASK) >> 12);
mmu_set_cam_entry(base_address, pg_size_bits, 0, 0, virtual_addr_tag);
mmu_flush_entry(base_address);
return status;
}
hw_status hw_mmu_tlb_add(const void __iomem *base_address,
u32 physical_addr, u32 physical_addr,
u32 virtual_addr, u32 virtual_addr,
u32 page_sz, u32 page_sz,
...@@ -503,20 +440,8 @@ hw_status hw_mmu_pte_clear(const u32 pg_tbl_va, u32 virtual_addr, u32 page_size) ...@@ -503,20 +440,8 @@ hw_status hw_mmu_pte_clear(const u32 pg_tbl_va, u32 virtual_addr, u32 page_size)
return status; return status;
} }
/* mmu_flush_entry */
static hw_status mmu_flush_entry(const void __iomem *base_address)
{
hw_status status = 0;
u32 flush_entry_data = 0x1;
/* write values to register */
MMUMMU_FLUSH_ENTRY_WRITE_REGISTER32(base_address, flush_entry_data);
return status;
}
/* mmu_set_cam_entry */ /* mmu_set_cam_entry */
static hw_status mmu_set_cam_entry(const void __iomem *base_address, static hw_status mmu_set_cam_entry(void __iomem *base_address,
const u32 page_sz, const u32 page_sz,
const u32 preserved_bit, const u32 preserved_bit,
const u32 valid_bit, const u32 valid_bit,
...@@ -536,7 +461,7 @@ static hw_status mmu_set_cam_entry(const void __iomem *base_address, ...@@ -536,7 +461,7 @@ static hw_status mmu_set_cam_entry(const void __iomem *base_address,
} }
/* mmu_set_ram_entry */ /* mmu_set_ram_entry */
static hw_status mmu_set_ram_entry(const void __iomem *base_address, static hw_status mmu_set_ram_entry(void __iomem *base_address,
const u32 physical_addr, const u32 physical_addr,
enum hw_endianism_t endianism, enum hw_endianism_t endianism,
enum hw_element_size_t element_size, enum hw_element_size_t element_size,
...@@ -556,7 +481,7 @@ static hw_status mmu_set_ram_entry(const void __iomem *base_address, ...@@ -556,7 +481,7 @@ static hw_status mmu_set_ram_entry(const void __iomem *base_address,
} }
void hw_mmu_tlb_flush_all(const void __iomem *base) void hw_mmu_tlb_flush_all(void __iomem *base)
{ {
__raw_writel(1, base + MMU_GFLUSH); __raw_writel(1, base + MMU_GFLUSH);
} }
...@@ -42,44 +42,41 @@ struct hw_mmu_map_attrs_t { ...@@ -42,44 +42,41 @@ struct hw_mmu_map_attrs_t {
bool donotlockmpupage; bool donotlockmpupage;
}; };
extern hw_status hw_mmu_enable(const void __iomem *base_address); extern hw_status hw_mmu_enable(void __iomem *base_address);
extern hw_status hw_mmu_disable(const void __iomem *base_address); extern hw_status hw_mmu_disable(void __iomem *base_address);
extern hw_status hw_mmu_num_locked_set(const void __iomem *base_address, extern hw_status hw_mmu_num_locked_set(void __iomem *base_address,
u32 num_locked_entries); u32 num_locked_entries);
extern hw_status hw_mmu_victim_num_set(const void __iomem *base_address, extern hw_status hw_mmu_victim_num_set(void __iomem *base_address,
u32 victim_entry_num); u32 victim_entry_num);
/* For MMU faults */ /* For MMU faults */
extern hw_status hw_mmu_event_ack(const void __iomem *base_address, extern hw_status hw_mmu_event_ack(void __iomem *base_address,
u32 irq_mask); u32 irq_mask);
extern hw_status hw_mmu_event_disable(const void __iomem *base_address, extern hw_status hw_mmu_event_disable(void __iomem *base_address,
u32 irq_mask); u32 irq_mask);
extern hw_status hw_mmu_event_enable(const void __iomem *base_address, extern hw_status hw_mmu_event_enable(void __iomem *base_address,
u32 irq_mask); u32 irq_mask);
extern hw_status hw_mmu_event_status(const void __iomem *base_address, extern hw_status hw_mmu_event_status(void __iomem *base_address,
u32 *irq_mask); u32 *irq_mask);
extern hw_status hw_mmu_fault_addr_read(const void __iomem *base_address, extern hw_status hw_mmu_fault_addr_read(void __iomem *base_address,
u32 *addr); u32 *addr);
/* Set the TT base address */ /* Set the TT base address */
extern hw_status hw_mmu_ttb_set(const void __iomem *base_address, extern hw_status hw_mmu_ttb_set(void __iomem *base_address,
u32 ttb_phys_addr); u32 ttb_phys_addr);
extern hw_status hw_mmu_twl_enable(const void __iomem *base_address); extern hw_status hw_mmu_twl_enable(void __iomem *base_address);
extern hw_status hw_mmu_twl_disable(const void __iomem *base_address); extern hw_status hw_mmu_twl_disable(void __iomem *base_address);
extern hw_status hw_mmu_tlb_flush(const void __iomem *base_address, extern hw_status hw_mmu_tlb_add(void __iomem *base_address,
u32 virtual_addr, u32 page_sz);
extern hw_status hw_mmu_tlb_add(const void __iomem *base_address,
u32 physical_addr, u32 physical_addr,
u32 virtual_addr, u32 virtual_addr,
u32 page_sz, u32 page_sz,
...@@ -97,7 +94,7 @@ extern hw_status hw_mmu_pte_set(const u32 pg_tbl_va, ...@@ -97,7 +94,7 @@ extern hw_status hw_mmu_pte_set(const u32 pg_tbl_va,
extern hw_status hw_mmu_pte_clear(const u32 pg_tbl_va, extern hw_status hw_mmu_pte_clear(const u32 pg_tbl_va,
u32 virtual_addr, u32 page_size); u32 virtual_addr, u32 page_size);
void hw_mmu_tlb_flush_all(const void __iomem *base); void hw_mmu_tlb_flush_all(void __iomem *base);
static inline u32 hw_mmu_pte_addr_l1(u32 l1_base, u32 va) static inline u32 hw_mmu_pte_addr_l1(u32 l1_base, u32 va)
{ {
......
...@@ -53,8 +53,8 @@ struct cfg_hostres { ...@@ -53,8 +53,8 @@ struct cfg_hostres {
u32 chnl_buf_size; u32 chnl_buf_size;
u32 num_chnls; u32 num_chnls;
void __iomem *per_base; void __iomem *per_base;
u32 per_pm_base; void __iomem *per_pm_base;
u32 core_pm_base; void __iomem *core_pm_base;
void __iomem *dmmu_base; void __iomem *dmmu_base;
}; };
......
...@@ -47,8 +47,8 @@ ...@@ -47,8 +47,8 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
/* TODO -- Remove, once BP defines them */ /* TODO -- Remove, once omap-iommu is used */
#define INT_DSP_MMU_IRQ 28 #define INT_DSP_MMU_IRQ (28 + NR_IRQS)
#define PRCM_VDD1 1 #define PRCM_VDD1 1
......
...@@ -667,10 +667,10 @@ int drv_request_bridge_res_dsp(void **phost_resources) ...@@ -667,10 +667,10 @@ int drv_request_bridge_res_dsp(void **phost_resources)
OMAP_DSP_MEM3_SIZE); OMAP_DSP_MEM3_SIZE);
host_res->per_base = ioremap(OMAP_PER_CM_BASE, host_res->per_base = ioremap(OMAP_PER_CM_BASE,
OMAP_PER_CM_SIZE); OMAP_PER_CM_SIZE);
host_res->per_pm_base = (u32) ioremap(OMAP_PER_PRM_BASE, host_res->per_pm_base = ioremap(OMAP_PER_PRM_BASE,
OMAP_PER_PRM_SIZE); OMAP_PER_PRM_SIZE);
host_res->core_pm_base = (u32) ioremap(OMAP_CORE_PRM_BASE, host_res->core_pm_base = ioremap(OMAP_CORE_PRM_BASE,
OMAP_CORE_PRM_SIZE); OMAP_CORE_PRM_SIZE);
host_res->dmmu_base = ioremap(OMAP_DMMU_BASE, host_res->dmmu_base = ioremap(OMAP_DMMU_BASE,
OMAP_DMMU_SIZE); OMAP_DMMU_SIZE);
......
...@@ -304,8 +304,7 @@ int node_allocate(struct proc_object *hprocessor, ...@@ -304,8 +304,7 @@ int node_allocate(struct proc_object *hprocessor,
u32 pul_value; u32 pul_value;
u32 dynext_base; u32 dynext_base;
u32 off_set = 0; u32 off_set = 0;
u32 ul_stack_seg_addr, ul_stack_seg_val; u32 ul_stack_seg_val;
u32 ul_gpp_mem_base;
struct cfg_hostres *host_res; struct cfg_hostres *host_res;
struct bridge_dev_context *pbridge_context; struct bridge_dev_context *pbridge_context;
u32 mapped_addr = 0; u32 mapped_addr = 0;
...@@ -581,6 +580,9 @@ int node_allocate(struct proc_object *hprocessor, ...@@ -581,6 +580,9 @@ int node_allocate(struct proc_object *hprocessor,
if (strcmp((char *) if (strcmp((char *)
pnode->dcd_props.obj_data.node_obj.ndb_props. pnode->dcd_props.obj_data.node_obj.ndb_props.
stack_seg_name, STACKSEGLABEL) == 0) { stack_seg_name, STACKSEGLABEL) == 0) {
void __iomem *stack_seg;
u32 stack_seg_pa;
status = status =
hnode_mgr->nldr_fxns. hnode_mgr->nldr_fxns.
get_fxn_addr(pnode->nldr_node_obj, "DYNEXT_BEG", get_fxn_addr(pnode->nldr_node_obj, "DYNEXT_BEG",
...@@ -608,14 +610,21 @@ int node_allocate(struct proc_object *hprocessor, ...@@ -608,14 +610,21 @@ int node_allocate(struct proc_object *hprocessor,
goto func_end; goto func_end;
} }
ul_gpp_mem_base = (u32) host_res->mem_base[1];
off_set = pul_value - dynext_base; off_set = pul_value - dynext_base;
ul_stack_seg_addr = ul_gpp_mem_base + off_set; stack_seg_pa = host_res->mem_phys[1] + off_set;
ul_stack_seg_val = readl(ul_stack_seg_addr); stack_seg = ioremap(stack_seg_pa, SZ_32);
if (!stack_seg) {
status = -ENOMEM;
goto func_end;
}
ul_stack_seg_val = readl(stack_seg);
iounmap(stack_seg);
dev_dbg(bridge, "%s: StackSegVal = 0x%x, StackSegAddr =" dev_dbg(bridge, "%s: StackSegVal = 0x%x, StackSegAddr ="
" 0x%x\n", __func__, ul_stack_seg_val, " 0x%x\n", __func__, ul_stack_seg_val,
ul_stack_seg_addr); host_res->mem_base[1] + off_set);
pnode->create_args.asa.task_arg_obj.stack_seg = pnode->create_args.asa.task_arg_obj.stack_seg =
ul_stack_seg_val; ul_stack_seg_val;
......
...@@ -223,8 +223,13 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, ...@@ -223,8 +223,13 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
cmem = zs_map_object(zram->mem_pool, zram->table[index].handle, cmem = zs_map_object(zram->mem_pool, zram->table[index].handle,
ZS_MM_RO); ZS_MM_RO);
ret = lzo1x_decompress_safe(cmem, zram->table[index].size, if (zram->table[index].size == PAGE_SIZE) {
memcpy(uncmem, cmem, PAGE_SIZE);
ret = LZO_E_OK;
} else {
ret = lzo1x_decompress_safe(cmem, zram->table[index].size,
uncmem, &clen); uncmem, &clen);
}
if (is_partial_io(bvec)) { if (is_partial_io(bvec)) {
memcpy(user_mem + bvec->bv_offset, uncmem + offset, memcpy(user_mem + bvec->bv_offset, uncmem + offset,
...@@ -342,8 +347,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, ...@@ -342,8 +347,11 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
goto out; goto out;
} }
if (unlikely(clen > max_zpage_size)) if (unlikely(clen > max_zpage_size)) {
zram_stat_inc(&zram->stats.bad_compress); zram_stat_inc(&zram->stats.bad_compress);
src = uncmem;
clen = PAGE_SIZE;
}
handle = zs_malloc(zram->mem_pool, clen); handle = zs_malloc(zram->mem_pool, clen);
if (!handle) { if (!handle) {
......
...@@ -618,4 +618,20 @@ static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev) ...@@ -618,4 +618,20 @@ static inline struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
}; };
#endif #endif
/**
* IIO_DEGREE_TO_RAD() - Convert degree to rad
* @deg: A value in degree
*
* Returns the given value converted from degree to rad
*/
#define IIO_DEGREE_TO_RAD(deg) (((deg) * 314159ULL + 9000000ULL) / 18000000ULL)
/**
* IIO_G_TO_M_S_2() - Convert g to meter / second**2
* @g: A value in g
*
* Returns the given value converted from g to meter / second**2
*/
#define IIO_G_TO_M_S_2(g) ((g) * 980665ULL / 100000ULL)
#endif /* _INDUSTRIAL_IO_H_ */ #endif /* _INDUSTRIAL_IO_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment