(unsigned long long)taddr, size);
#endif
+ /* Check for bypass */
+ if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) {
+ cpu_physical_memory_write(taddr, buf, size);
+ return 0;
+ }
+
while (size) {
uint64_t tce;
uint32_t lsize;
(unsigned long long)taddr, size);
#endif
+ /* Check for bypass */
+ if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) {
+ cpu_physical_memory_read(taddr, buf, size);
+ return 0;
+ }
+
while (size) {
uint64_t tce;
uint32_t lsize;
return 0;
}
+/* "quiesce" handling */
+
+static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
+{
+ dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS;
+
+ if (dev->rtce_table) {
+ size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
+ * sizeof(VIOsPAPR_RTCE);
+ memset(dev->rtce_table, 0, size);
+ }
+
+ dev->crq.qladdr = 0;
+ dev->crq.qsize = 0;
+ dev->crq.qnext = 0;
+}
+
+static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token,
+ uint32_t nargs, target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ VIOsPAPRBus *bus = spapr->vio_bus;
+ VIOsPAPRDevice *dev;
+ uint32_t unit, enable;
+
+ if (nargs != 2) {
+ rtas_st(rets, 0, -3);
+ return;
+ }
+ unit = rtas_ld(args, 0);
+ enable = rtas_ld(args, 1);
+ dev = spapr_vio_find_by_reg(bus, unit);
+ if (!dev) {
+ rtas_st(rets, 0, -3);
+ return;
+ }
+ if (enable) {
+ dev->flags |= VIO_PAPR_FLAG_DMA_BYPASS;
+ } else {
+ dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS;
+ }
+
+ rtas_st(rets, 0, 0);
+}
+
+static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
+ uint32_t nargs, target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ VIOsPAPRBus *bus = spapr->vio_bus;
+ DeviceState *qdev;
+ VIOsPAPRDevice *dev = NULL;
+
+ if (nargs != 0) {
+ rtas_st(rets, 0, -3);
+ return;
+ }
+
+ QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+ dev = (VIOsPAPRDevice *)qdev;
+ spapr_vio_quiesce_one(dev);
+ }
+
+ rtas_st(rets, 0, 0);
+}
+
static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
{
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
spapr_register_hypercall(H_SEND_CRQ, h_send_crq);
spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
+ /* RTAS calls */
+ spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
+ spapr_rtas_register("quiesce", rtas_quiesce);
+
for (qinfo = device_info_list; qinfo; qinfo = qinfo->next) {
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
typedef struct VIOsPAPRDevice {
DeviceState qdev;
uint32_t reg;
+ uint32_t flags;
+#define VIO_PAPR_FLAG_DMA_BYPASS 0x1
qemu_irq qirq;
uint32_t vio_irq_num;
target_ulong signal_state;
void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg,
qemu_irq qirq, uint32_t vio_irq_num);
+int spapr_tce_set_bypass(uint32_t unit, uint32_t enable);
+void spapr_vio_quiesce(void);
+
#endif /* _HW_SPAPR_VIO_H */